Background
I am writing an application which has two distinct functions.
Load a GPX file and direct the user to follow the route defined in the file, by pointing the correct direction of travel and distance. Then marking the waypoint as reached and selecting the next as and when necessary.
Display the route on the standard maps widget.
Current Thinking
My current design is to have three tabs: menu, location, map. Where menu is used for loading the gpx file and amending settings; location gives the current location and direction to travel; and maps is of course the map widget with the route overlay.
So this gives four activities (the main app, and the three tabs).
I am going to need some routine to take the current location and apply logic to it to work out the current best position. Another routine to keep track of the route and what waypoints have been met. My thinking is to have two separate threads (one for location,one for route tracking) spawned from the main activity which have methods which can be called by any of the activities e.g. get position. The route tracking should also use some callback mechanism or event mechanism to inform the UI when a waypoint has been reached.
This way the user interface can update as and when needed, but also responds to events driven from the location data.
Question
Does this seem a sensible set of decisions or is there something I haven't considered which will take me by surprise. Writing for a mobile phone is significantly different to my usual fare (having a UI makes a big change).
It might make more sense to have the location and route tracking logic implemented as bound services, rather than as threads spawned by one of your activities. See the Services guide topic for more info on how to set up and use a Service in your application.
Other than that, your approach seems pretty sound to me.
Related
I'm working on an Android piano "quiz" app - users tap on the piano keys and then click the yellow "check" button to submit the answer for evaluation and see the correct answer drawn on the piano. The main QuizActivity has this layout:
The upper part of the screen hosts a couple of controls (Text, submit buttons, etc.).
The lower part of the screen is occupied by a custom PianoView component, that handles drawing of the piano keyboard.
According to the MVVM principles, the PianoView should have its own PianoViewModel, that stores its state (i.e. currently pressed keys, highlighted keys, etc...) in a KeysStateRepository.
The enclosing QuizActivity should also have a QuizActivityViewModel, that handles the various controls (submitting an answer, skipping a question...).
The QuizActivityViewModel needs to be able to query the selected keys from the PianoView (or rather from its KeysStateRepository), submit them to the Domain layer for evaluation and then send the results back to the PianoView for visualization.
In other words, the QuizActivity's ViewModel should own/be a parent of the PianoView's ViewModel to facilitate communication and data sharing.
How can I model this parent-child relationship to communicate between the ViewModels?
AFAIK a ViewModel cannot depend on another ViewModel (What would I pass as the ViewModelStoreOwner to obtain a ViewModel in another Viewmodel?). I don't think it's possible to achieve with Dagger-Hilt at least.
Three solutions to work around this problem came to mind, all of them unusable:
1 - The official way of sharing data between Views
The Android dev docs recommend using a shared ViewModel to facilitate sharing of data between two Fragments / Views. However, this does not fit my use-case. The PianoView (or its ViewModel) should be the sole owner of its state with a Repository scoped to its ViewModel. Otherwise, the PianoView component would not be reusable. Consider for example another Activity, where I'd like to have two independent PianoView instances visible:
Reusing a Shared ViewModel from the quiz activity would be obviously wrong, because it contains irrelevant methods and logic (i.e. submitting quiz answers) and would not fit the two-keyboard scenario.
2 - Application-scoped repository
A similar problem was tackled on Reddit with a proposed solution of using a shared instance of the repository. However, using a #Singleton KeyStateRepository would once again prevent the two independent keyboards to display different data.
3(EDIT) - 2 duplicate repositories replicated by an Event Bus
I could in theory create 2 independent ViewModels and 2 KeyStateRepository instances. The ViewModels would subscribe to an event bus. Each time a ViewModel invokes a mutable operation on its repository, it would also fire an event and the operation would get replicated via the other ViewModel subscribed to the same event bus.
However, this feels like a fragile & complicated hack. I'd like to have a simple MVVM-compatible solution. I can't believe a simple parent-child relationship for two UI components is something unattainable in MVVM.
I think you got a decent answer from Pavlo up there, I'll just clarify what he meant with other words.
KeyStateRepository is a storage for the state of piano keys. There's nothing stopping you from making it to support N number of Pianos at the same time, this would solve the scenario where you have NNN Pianos on Screen, each with different keys pressed.
The PianoView should be contained in a Fragment, that should be your "unit". Why? Because you want a ViewModel to handle the state and events coming to/from the view. And a Fragment is the Android artifact provided for that regard. Think of it as an annoying piece of baggage you need. Android Devs used to call these things "Policy Delegates" because you delegate to these (a Fragment/Activity) some things you cannot do without "the framework" (the Android Framework, that is).
With this in mind, you have an Activity whose viewModel/State is handled independently. What State/Events do this viewModel handle? Things that are not in the PianoFragment/View(s). E.g. if you wanted to handle the back navigation, or a "record" button at the top, this is the activity's domain. What happens inside the "PianoView/Fragment" is not this activity's problem.
Now the Fragment that will contain the actual PianoView can be designed to contain "more than one" or just one. If you go for more than one, then the PianoContainerFragment will be designed with a ViewModel designed to handle more than one PianoView (so each view will have a "name/key") and the KeyStateRepo will be able to handle the "CRUD" operations of any Piano View you throw at. The ViewModel will sit in between, dispatching events for different "subscribed" views.
If you elect to go for "one fragment contains one piano view", then it's a similar architecture, but now handling the multiple "fragments" in one "activity" is now responsibility of the Activity (and its view model). But remember, the PianoViews (via a Fragment either shared or not) talk to a ViewModel that can be shared among piano views, that talks to a common KeyState Repo. The activity coordinates the views and other Android things (navigation, etc.) but the views operate independently, even of each other.
You don't really need a shared viewModel I think, in fact, I wouldn't do it until really needed, the more you separate things, the less the chances of "violating" one of the fancy patterns... but if you elect to use the PianoViewModel as a shared among all views, that's perfectly acceptable, you're going to have to include the Piano "Name" to differentiate whose events are for whom.
In other words (showing with ONE PianoViewModel for ASCII Simplicity),
// One QuizActivityViewModel, Multiple Fragments:
Activity -> PianoFragment (PianoView)|
| <-> PianoViewModel <-> KeyRepo
PianoFragment (PianoView)| /
-> QuizActivityViewModel <----------------------/
Here the QuizActivity creates N fragments (in a list maybe?). These fragments internally initialize their pianoView and connect to a PianoViewModel (can be shared like in the graph above) or each can have its own. They all talk to the same Repo. The repo is your "single source of truth about what each "piano". What keys are pressed, and anything else you can think of (including a name/key to make it unique).
When QuizActivity needs to evaluate the state of these, it will ask (via its own viewModel) for the state of NN pianos.
Or
// 1 Act. 1 Frag. N Views.
Activity -> PianoFragment (PianoView)|
(PianoView)| <-> PianoViewModel <-> KeyRepo
-> QuizActivityViewModel <---------------------------/
With these, the QuizActivity (which created the pianos to begin with as well), also knows the keys of the pianos that will/are displayed. It can talk to its viewModel that talks to the same KeysRepo (you only have one of these and that's fine). So it can still handle the "nav" buttons and it can ask (via its QuizActVM) what the current state of the Keys are (for all involved pianos). When a Piano key event is fired in a PianoView, the PianoViewModel will receive the event (what key was touched, in what piano); the KeyStateRepo will record this, and perhaps update a flow {} with the events coming from the pianos...
The Flow will be expressed in a sealed class which will contain enough information for both QuizActivity + VM (to perhaps perform a real-time validation), and to the PianoViewModel to update the state and push a new state to the PianoFragment (Which will update the state of its view(s)).
This is all common to either method. I hope this clarifies the sequence.
Does this make sense to you?
Edit
In a multiple architecture activity if you wan't PianoViews to have ViewModels and your ActivityViewModel to know about them - don't use Dagger injection with them but create PianoViewModels inside an ActivityViewModel and assign some callback to them on the stage of creation - thus you will have an access to them and will be able to listen to their events and influence their behaviour as well as save their state, from inside the ActivityViewModel. It is not an uncommon and in some cases even a correct approach. Dagger - is a mere instrument that is not intended to be used everywhere, but only there were it is needed. It is not needed to create PianoViewModels - you can inject all the needed stuff into the ActivityViewModel and pass all the needed elements to PianoViewModels constructors.
Also you don't need to wrap your Views into Fragments if you don't want to.
Edit end
You are making wrong assumptions based on a flawed architectural approach.
I am curious why do you need ActivityViewModel at all. View model should exist only for the elements that have some View. Current android development suggests that the Activity should not have a view representation and serve as a mere container of other views(Single activity principle). Depending on your architecture Activity may handle showing the loading state(progress bar) and some errors, but once again it should not contain anything that is being handled by other views. Thus PianoView should be a PianoFragment with its own ViewModel that handles access to its repository on the data layer via interactor on the domain layer.
The shared view model would work in case you would need one, and you would be using the Single activity principle with multiple fragments. Because Jetpack Navigation has the support of the shared view model out of the box. In the case of a shared view model - each fragment would have its own view model along with a shared one for communication. Each navigation graph could have a separate shared view model only for the fragments it contains.
Also regarding KeyStateRepository - you need only one of those(or a Dagger #Scoped multiple copies - but I do not recommend it). The only change should be - the addition of an extra key for each separate PianoView - to distinguish them inside a KeyStateRepository. To easily achieve that you may be using Room or some other file/memory/database cache mechanism.
Hence the initial problem of your app is not an inverted dependency of ActivityViewModel on a PianoViewModel, but a flawed architecture of the app and its inner interactions. If you want to continue work with your current architecture - there is no easy answer to your question, and almost every chosen solution would not be 'clean' enough to justify its usage.
I would do the following, if you don't want to tie the PianoViewModel to your ActivityViewModel, I'd just create an interface, which the ActivityViewModel implements, and the PianoVM could have a nullable reference to that interface. This way neither the implementation, nor the existence of the component would be required for the PianoViewModel to work.
How you get the ActivityViewModel is another question. Check out by activityViewModels() implementation for fragments, you probably can do the same with by viewModels() passing in the viewModelStore of the activity instead
I trying to make the app similar to Nissan Leaf Spy. This app receives data from bluetooth interface ELM 327. My goal is to collect data like:
Speed
Temperature
Power
Battery capacity
And some more data
And display them on real time chart using GraphView.
For one parameter is one chart in Activity. So there are at least as many Activities as parameters I need to display. My guess is to use
Android Services
to do work in background to co collect and save every data in different array via bluetooth. Of course when I change Activity to see another Activity the one that works will stop working and there will be no more real time.
The question is: is there any kind of 'superclass' that is always working or do I need to save this data using SQL? Or should I just use intent.putExtraString(key,value) and getIntent().getStringExtra(key). I will be grateful for your help!
About having different activities for different parameters, you need to have just one activity. You can have a graph and different ArrayLists with adapters for parameters and then use one of them to feed the graph according to the parameter selected say, from a Spinner.
To feed those ArrayLists is just as easy. You can have a Service running, for general data collection, with an AsyncTask inside it, which will keep the feed live for a selected parameter when the app is active and not in the background. The Service, by itself, can collect data in some sort of a buffer large enough to feed those graphs.
Remember, AsyncTasks are good for updating UI components without blocking the main thread.
EDIT: Look, if you have an activity (let's consider some other activity than main) where you're going to show the data or graph, you can have AsyncTask running as soon as you enter the activity(you can define a default parameter for a graph to be shown) or when you select from a drop down, giving you real-time data while you're on the activity.
The reason I am using AsyncTask for the live feed is that you can have different UI views and seamlessly integrate without any future problems and that it'd modularize Service into functionalities for serving Activity and would end when you close the app. The Service running in the background would primarily provide to a temp log file or be an InputStream source for AsyncTask when it runs after app launch or activity launch.
Okay, Activities build on top of Places. Places are "just URLs". But I am just not getting it how to use them properly..
There are no nested Activities "because YAGNI"; but how does it look like in this simple scenario:
Having a login page
Having an administration page that offers functionallity for
Add events to my company
Add items to my store
After a successful login the "main container" of the website is cleared and filled with the new content of the admin-activity. One thing that has to be changed here is the "display" of the ActivityMapper since now I got a navigation bar on the left side and a main-content Div on the right side.
I could just have a LoginActivity and an AdminActivity. That means I'd have urls like
/#LoginPlace:noParams
/#AdminPlace:eventManager
/#AdminPlace:itemManager
But that's silly imho because for real I would like to have something like this:
/#LoginPlace:noParams
/#AdminPlace:eventManager|storeId=1,langaugeId=2
/#AdminPlace:itemManager|storeId=1,langaugeId=2,page=0
But that would require my AdminActivity to break up the URL and look out for all this different types of URLs, right? What I mean is something like this:
private AdministrationActivity administrationActivity;
#Override
public Activity getActivity(Place place) {
if (place instanceof LoginPlace) {
return new LoginActivity((LoginPlace) place);
} else if (place instanceof AdministrationPlace) {
if(this.adminActivity== null) {
this.adminActivity= new AdministrationActivity((AdministrationPlace) place);
} else {
this.adminActivity.updateMainContent(((AdministrationPlace) place).getUrl());
}
return this.adminActivity;
}
return null;
}
Where now adminActivity.updateMainContent() will have to do the parsing for all places in order to display the correct content.
This would be the solution:
/#LoginPlace:noParams
/#EventManagerPlace:storeId=1,langaugeId=2
/#ItemManagerPlace:storeId=1,langaugeId=2,page=0
But(!) now I need an activity for each place, right? And I am just not sure if there are equally as many places as there are activities. I thought that one activity can navigate to different places.
So how are Places and Activities supposed to used?
The first questions you have to ask yourself is "where will the user possibly go?". As I understand it, you at a minimum have:
list of events, with possible filter/selection criteria and paging attributes
list of items, with possible filter/selection criteria and paging attributes
Maybe you'll also have places like "details of an event" (maybe even split between read-only details and editable details, if the user will switch between both states; if the state depends on who the user is, then this is IMO the same place, and actions the user can do are different), "details of an item", "form to add an event", "form to add an item".
To me, login is a cross-cutting feature, it's not something the user comes to doing in your app (it's not a business use-case, not an "activity" that's part of the user's job). You can still choose to use a place and activity for login though; so let's add that to the list: "login form" (definitely not how I'd do it, but that's another story).
Now you can choose how you want to represent those places as GWT Place objects: you can have one Place subclass with a property telling you which exact "place" you're on (basically what your AdminPlace:eventManager token suggests), or one Place subclass per "place" (what your EventManagerPlace token suggests). This is entirely independent of whether you'll have one or several activities.
The next question is about the various areas of the screen, that'll map to ActivityManagers: what parts of the screen do change when navigating? Maybe they do not all change at the same time / under the same conditions.
So for example, should your navigation bar be within the activity or not? If you can put it outside (because it's reused), do it. It actually need not even be an activity if it's always the same (modulo the selected item). In any case, it's probably a good idea to make it a singleton (or similar) and listening to PlaceChangeEvents to select the appropriate item (not necessarily a "singleton", but at least not recreated on each navigation). The advantage of putting the navigation bar outside the activities is that if you finally decide to have it vertical rather than horizontal (or the other way around), and/or collapsible, you won't have to change your activities (separation of concern). If you ever have to build a mobile app, you could even have a "menu" place on that app that displays the navigation bar full-page and swaps it for the other activities when navigating.
So we now have 2 display regions, i.e. 2 ActivityManagers, and their respective ActivityMappers. Or maybe just one display region for the "main content", and the navigation bar is not an Activity. The next step is to determine exactly what changes and when; i.e. when I go to place X, I need to have that thing in that area, and that other thing in that one; those "things" are your activities.
The key to "model" your Activities is to think about the things the user does (activities) and focus on one of them. But Activities are also tied to how the user interacts with the application, and the navigation (e.g. when adding an item, does the form appears in a popup above the list, or replaces the list); so if you want to really completely separate concerns, you'd probably create some object to manage the list of events/items and have a really thin Activity that only instantiates and manages that object. That's probably over-engineered as a starting point though, and it'll be relatively easy to factor the thing out of the Activity later if you feel it's needed.
I like (and that's basically how the feature has been designed) to have disposable activities. In my ActivityMapper, everything from the Place that the Activity needs to know is passed to its constructor; the Activity doesn't have to know the current place (or listen to place changes), and is not "mutated" by the ActivityMapper. There can of course be exceptions to the rule, for various reasons. If you need to share state between "places" for a given activity (e.g. data caches, etc.), you don't necessarily have to reuse it, you can share the state via shared stateful objects and keep the activity mostly stateless.
Anyway, your idea of a big AdminActivity that itself swaps a big part of its content depending on the current place is akin to nesting.
In the end, there's no one-size-fits-all, and you'll have to try and pick the strategy⋅ies that best fit your needs.
Last, but not least, don't design your place with a generic getUrl() that needs to be parsed; parse everything in your PlaceTokenizers; nothing else than the tokenizers need to know how the place will look like in your URL (and you're not even forced to use a PlaceHistoryHandler to begin with, so your places might not even ever end up in the URL –your places won't be bookmarkable then and you won't be able to navigate in the app through the browser history)
The key concept is separation of concerns.
I'd suggest you probably do want one Activity per Place. There is generally a rough one to one relationship but they are split due to separation of concerns and so you can pass around a Place without an Activity.
Adding parameters is sadly not supported by standard GWT. We created our own simple one based on UrlBuilder.
There is a long standing issue for this https://code.google.com/p/google-web-toolkit/issues/detail?id=2422 (old issue tracker) which has other thoughts and links.
Once it is up and running it works really nicely. I like using strongly typed objects and goTo rather than sticking URLs together.
The GWT JavaDocs for the PlaceHistoryHandler#DefaultHistorian are vague and cyclic:
Default implementation of PlaceHistoryHandler.DefaultHistorian.
This doesn't really tell us what it is, or what it does!
Then we have the PlaceHistoryMapper and the ActivityMapper objects. My understanding is that the PlaceHistoryMapper's job is to map URL tokens to Place, and that ActivityMapper maps those Places to Actvitity implementations.
So I ask: if these two Mappers take care of binding a URL token to a specific Activity, then what role does the DefaultHistorian play in all of this?
Javadoc is easy to correct at read time: DefaultHistorian is the default implementation of Historian.
To understand how they all play together, you first have to understand that places can work without history, and also without activities.
So, in the central place are places: PlaceController keeps a current Place (getWhere), which can be modified by goTo and broadcasts change events to an EventBus. Listeners can ask the user to confirm (PlaceChangeRequestEvent's setMessage) through Delegate (whose default implementation uses Window.confirm).
Built on top of PlaceRequestChangeEvent and PlaceChangeEvent are activities. You can have several ActivityManagers, each one with its ActivityMapper and a display region, displaying a different activity each for the same given/current place.
And on the other side, based on goTo and the above-mentioned events is history. PlaceHistoryHandler listens to events on both sides and either updates the history (through the Historian) or updates the places (through PlaceController's goTo). The PlaceHistoryMapper maps between both worlds. The default implementation of the Historian (DefaultHistorian) uses com.google.gwt.user.client.History and com.google.gwt.user.client.Window#addWindowClosingHandler. You could provide your own implementation that uses HTML5's pushState and onpopstate for instance.
See:
http://blog.ltgt.net/gwt-21-places/
http://blog.ltgt.net/gwt-21-places-part-ii/
http://blog.ltgt.net/gwt-21-activities/
http://blog.ltgt.net/gwt-21-activities-nesting-yagni/
We are developing a vehicle tracking system. Like every VTS, we have GPS devices fitted into the vehicles which keep sending location information to the server. On server, our TCP communicator process keeps reading that data and saves it into the database
Now, we need to check for some set of rule to trigger alerts for the vehicles, e.g We need alert when vehicle reaches to a particular location, if vehicle crosses specific speed-limit,etc.
Can you please suggest the best way to implement it?
We have thought of some ways to implement it,
1. Our TCP communicator, when receives the location, should check for the alerts.
2. There will be a process which will keep running every 15 minutes and check the location details in that 15 minutes for alerts.
I am looking for the suggestions to implement it, logic-wise as well as technology-wise. e.g. Whether we should use Drools or not?, etc.
Somebody from FedEx actually presented something like this in a JavaOne conference I attended a couple of years back.
Basically, the idea was, yes, using Drools Expert + Fusion to perform CEP (complex events processing) on vehicle location data.
As far as I can recall, a vehicle would periodically (every couple of seconds even) send its GPS coordinates to the engine (an event) which would then be digested by the rules engine, and depending on the rules could trigger certain actions such as raising alerts ("vehicle is stalled" or "out of course") or sending notifications ("vehicle will arrive at destination in ~15 minutes").
(Google for "drools fusion cep vehicle tracking" uncovers this presentation which should give you few more details or at least provide some insight.)
the way Drools work, is that you fill in alot of objects into the "Working Memory" of Drools. While you fill in the objects, Drools will find out which rules "fires" on the objects and stores the objects in a Rete-Tree. When you are finished putting the objects in the memory and you fire all rules, Drools will process the code you wrote corresponding to the rule.
I would suggest, that you make an object with all the data recieved from the vehicle necessary for your rules and put it in the working memory.
In Drools you should make many small rules, each just checking one thing and acting on the result.
It is not a good practice to let Drools get data needed for evaluation, but I can't see any problems in letting Drools trigger some events, that send messages to a vehicle or some other system. (I guess that should happen async, so that you don't slow down Drools) In fact, Drools offers you to hook up an eventlistener.
There's no reason to run every 15 minutes. That will introduce delay in the triggers and also result in bursts of load every 15 minutes followed be periods of no load.
You can have a flag in your database for new alert rules and new location data. When you scan for events, you can use a two-pass approach. Check all new rules against all location data and mark them no longer new. Then check all new location data against existing rules and mark them no longer new.
You can run this as often as you like. Ideally, you wouldn't wait that long because the longer you wait, the more work you accumulate.
As for having the TCP communicator check for relevant alerts over the scan the database periodically approach, the main advantage would be alerts would be immediate. The disadvantage would be that alert processing would slow down the TCP communicator path and you would be locked into a "one update means one check for alerts" model.
In the "scan the database" approach, if load gets too high, you can wind up checking for alerts only on every so many updates from high-frequency update sources. This naturally deals with load by reducing the amount of work needed, but it could result in a missed alert.
I think all the approaches you're considering will work fine.