I am currently researching for better ways to handle events in my app.
Currently I have multiple listeners that are subscribing and unsubscribing to interesting objects on different events.
E.g. on a button click a listener is created, that listens on a client object, if a operation succeeded (in that case it automatically unregisters itself) or if a non fatal error occurs (in that case it automatically retries the operation).
The client object in turn is starting a android service that can emit different status events, that should result in the user interface updating itself or alternatively show notifications, if the app is currently not visible.
In my app I have a really big listener clutter, that is not easy to follow and that is not working on all occasions.
To resolve this issue I would like to implement a event bus with RxJava that hopefully reduces the complexity of my application.
The problem:
Is it possible with RxJava to have a fallback observer for a observable, to react to events, if no other observer is available?
E.g. All activities/fragments register themselves to get informed about certain events, so they can update the UI, if necessary.
When a activity/fragment is created/destroyed it automatically registers/unregisters itself from the event bus.
If the app is now in background, there should be no observers registered anymore. In that case only I would like to use a fallback observer that is handling those events.
I would like to achieve the following:
If in foreground: On event, update the UI.
If in background: On event, show toast / notification.
In my opinion your app shouldn't show anything when it's in the background (user is not interested in it anymore, or is doing something else, so don't spam him with toasts (as he probably would not even know which application raised this toast)).
However,
You can solve this problem with Subject. Let say you have MyServiceErrorHandler class with PublishSubject> inside, so every time there is some part of UI is visible and capable of showing error is should be subscribed to this subject. Then you can expose method like onError(Throwable t) which will call subject.hasObservers(). If yes it pushes data to subject (so it will emit an event to currently subscribed UI) if no you can do some fallback thing (like displaying toast/notification/logging something/etc). This solution is however error prone to rotation as you may receive your result while screen is rotating (thus not subscribed yet)
You can extend this approach a little bit and use a BehaviourSubject which will replay it's last event for every subscriber (pretty handy in case of screen rotation). So you're posting event to this subject even though there are none subscribers, and when user opens this app back again (and one of your UI element will subscribe) it will receive last event with error (so you can show it properly). But in that solution you would need a little bit more logic to clear this subject in case of obsolete/already consumed errors (to prevent it from showing on every rotation/etc).
Related
I'm working on this project in Android in which an aspect requires a CountdownTimer with a foreground service. A few other answers on Stack Overflow mentioned that LocalBroadcastManager would be suitable for my needs.
The documentation in Android Developers, however, mentions that it has been deprecated. Any suggestions on what I should use in its place? The documentation mentioned about using LiveData, but I was wondering if there are any easier alternatives.
LocalBroadcastManager is basically an event bus with a lot of unnecessary ceremony around Intents and intent filters. So one replacement is easy, and functions quite similarly: you can use any event bus library. greenrobot's EventBus is a popular choice (here's a guide for it) and Guava also has one, if you're already using Guava (but Guava is pretty heavy to include just for an event bus).
But event buses suffer from the same problems that LocalBroadcastManager does that led to it being deprecated: it's global, it's not lifecycle-aware, and as your app gets larger, it becomes much more difficult to reason about the effects of a change to an event. For cases of observing data, LiveData solves this quite nicely because it's lifecycle-aware, so you won't get change notifications at the wrong time (like before your View is set up, or after onSaveInstanceState) - but it'll handle delivering the change notifications when you're in the right state again. It's also more tightly scoped - each piece of LiveData is accessed separately rather than having (typically) one event bus/LocalBroadcastManager for the entire app.
For cases where it's more of an event rather than a piece of data being changed, you can sometimes convert it to a piece of data. Consider if you have "login" and "logout" events - you could instead create a LiveData that stores an Account for logged-in users, and becomes null when the user is logged out. Components could then observe that.
There are certainly cases where it really is difficult to convert it to a piece of observable data (though I can't immediately think of any examples that would typically be used with an event bus patten). For those, consider writing your own listener interface, similar to how on-click listeners work.
For your example of a countdown timer, I think LiveData is a pretty straightforward solution, and will be much easier than an event bus or even LocalBroadcastManager would be. You can just have a LiveData of the timer's current value, and subscribe to it from whatever needs to show the value.
I'm trying to implement the MVP architecture in my app.
However, after reading some blogs and viewing some sample project samples, I'm not sure I completely understood where is the right place to detach the view, and what should be done once the view attached for the second time after an async operation.
Most of the examples I saw, just sum it all up with a view's null validation check after an async call.
I'll try to make my point clear with an example - Login/Registration by phone number (The main idea is the important thing, and not the example itself)
There is an activity which display a fragment - LoginFragment.
The user enters his phone number and tries to login.
If the user exits - he should get navigated to another activity (after entering the code received by sms..)
If the user doesn't exits, he should get navigated to registration process - RegistrationFragment.
If there was an error, a dialog with error message should appear, ErrorDialogFragment.
Now, in a happy flow where the user presses the login button and waits until the process complete, all good.
But, in a less happier flows (not so frequent ones, but definitely can't get ignored), the user presses the login button and after that presses the home button or alternatively gets a phone call.
In scenario 1, where we attach/detach the view in onCreate/onDestroy, once the async login operation finish and we should replace to RegistrationFragment or show ErrorDialogFragment, there is a chance we will meet the famous IllegalStateException:
getting exception "IllegalStateException: Can not perform this action after onSaveInstanceState"
In scenario 2, where we attach/detach the view in onResume/onPause, once the async login operation finish we won't be able to replace fragment or show a dialog because the view is already detached.
In this case, I'm not sure what is the right thing to do.
Should we go with scenario 1 and commit the transaction with commitallowingstateloss?
I'm afraid it is a bad idea.
Or Should we go with scenario 2. In this scenario, we should act accordingly when view attached again, which means saving states (RegistrationRequied, ErrorHasOccured, LoginProcessStillRunning, etc..) in the Presenter/Interactor.
Can someone can shed some light regarding this?
Thanks in advance!
Oh the joys of the Android lifecycle. I feel your pain.
In my personal experience, resorting to commitAllowingStateLoss is usually a symptom of trying to update your Ui (View) while in the background (and as you note, the ui may be destroyed).
What I would suggest is that you don't try to update your ui without checking if the activity has been backgrounded (onStop or onPause depending on the situation). If your ui has been backgrounded, remember the changes you need to make and do them when your Ui is reconnected (onStart or onResume depending on the situation).
In essence I'm saying you should follow Scenario 2. And yes. You will have to save quite a bit of state somehow.
Unfortunately this isn't easy and there are many approaches to doing this ranging from using event buses, all the way through to using RxJava.
Every approach has it's advantages and flaws and they are all really too complex to discuss in detail in a single post.
However, I have a blog post I wrote some time ago on a way of doing this in a way that doesn't require additional libraries.
It's a little out of date now, but it may give you some ideas: A Simple MVP aproach for Android
All the best.
Kind regards,
Chris.
I'm constructing an API which is going to be used by an Android and an iPhone app. The app gets a list of events which can regularly be updated. There are currently two ideas.
Creating it using pagination so that it first loads the first 10 events to load results on the screen, and when the user scrolls further it should load more events. I then regularly poll the API to see if there are any new events.
First get the paginated list of id's of events (also first 10), after which the apps should get the full event details in separate threads using one call for every event. In that way it can load all events simultaneously which supposedly makes it faster.
I tend to lean more towards the first solution because it's more simple, but somebody else said the second is a way better idea. I have the idea that the separate threads only add complexity to the case and don't increase the speed significantly. I know that the best way to know is to test it, but building both and testing it takes a lot of time. I therefore wonder whether there are any best practices in getting a continuously updated list of events from an API.
So; which of the two do you think would be best and why?
It depends on the amount of data your events contain. If each event description is only a few fields don't bother to load each event in a separate thread, the overhead will kill any possible performance gain - just get all data in the get events request.
If it is a lot of data per event description, you can argue whether you really want to preload all event descriptions before the user selects an event - probably the user will never click on any of the events, then you did load the data for nothing.
That said, it is also not a bad idea to prepare your API to enable both: Get a list of short event descriptions and a call to get event details for a certain event (or a list of event ids), or get a list which contains the full event descriptions.
Is it good practice to use Otto event bus bi-directionally?
I mean, send events from controller to view, and view to controller?
Or is it just meant to publish results meaning its purpose is only events from controller to view?
Thanks
Good question. Here is my thoughts on this. I use Otto for a while and use it bi-directionally. From my experience there is nothing against doing this. I have just defined couple of rules helping me keep everything under control.
One-to-many pattern must be confirmed. I mean here, that one producer should normally notify multiple subscribers. Of course, at different point in time there can be zero or more subscribers. But if you have a case, where by-design maximum number of subscribers is just one, then you trying to dispatch rather a "command", than an "event". For such cases I would use a direct call instead of posting a event.
Another thing to avoid should be a situation, when one event triggers another event, which, in turn, triggers first event again. You can run in infinite event chain here. This might happen when same class has the both subscriber and producer methods. If I have such classes, I try to keep those methods as independent as possible.
And of course I always use Android components' lifecycle to register and unregister publishers and subscribers dynamically. I start with onResume() and onPause() methods and, if needed, I'm going up to onStart() or even onCreate().
I'm developing an app which interacts with phone's WiFi, Bluetooth, Mobile Network.
The app is mainly a Service, and the GUI doesn't play a central role.
The core of the app, and the principal method of the service class is a single method which receives all intents that the app needs to receive:
public void handleIntent(Intent intent){
It then extracts the intent's action and calls a specific handler method for the corresponding intent's action, for instance when receiving a SCREEN_ON, it would call
private void handleScreenOn(){
Problem is that some tasks on the phone take some time, so that some other events may occur in the middle of the processing of the task, that should change processing.
For instance, turning ON the Wifi would take a couple of seconds, sending several intents WIFI_STATE_CHANGED_ACTION before it's actually completed. In the middle of the WiFi being enabled, the user can turn off the screen so that a SCREEN_OFF intent would be received.
Now say that my app's goal is to turn off WiFi when screen gets turned Off. There is a situation where a problem occurs:
Initial situation: Screen is On, WiFi is Off
User toggles WiFi setting to enable it. Wifi starts getting enabled
User almost immediately turns screen Off
The app receives the SCREEN_OFF intent but since WiFi is not enabled yet, then it believes that there is no need to disable it
Wifi enabling gets finished, and Wifi stays enabled despite the screen being off.
How to solve it?
Currently, in step 5, when Wifi gets finally enabled, I would test whether screen is off or not to turn off wifi again.
This solution requires many if / else handling all possible cases.
I'm sure there must be some cleaner way of doing it, handling a stack of intents, or something like this...
Anyone with some good design patter or good advice on how to do it cleanly?
Consider sending an "action completed" event whenever you (asynchronously) complete the reaction to some event. Now you can add some logic in handleIntent() to achieve a consistent state. The logic is at a central position in your components and code duplication is avoided.
Alternatively you can try to serialize your events: i.e. when an event occurs which may invalidate the outcome of some not yet finished action (you need to manage a list of not completed action, completion can be detected as outlined above) postpone its handling until all those actions are completed. To decide which events may depend on other events a simple, static lookup-table should suffice.
Another approach would be to maintain the state of the entities (either all of them, or just those that are asynchronous) being managed. For those that are asynchronous, the state should not be binary (ON|OFF), but rather have at least 3 or 4 states: ON, TURNING_ON, OFF, TURNING_OFF. Then in your example step 4, when you receive the SCREEN_OFF, check for the WIFI states ON or TURNING_ON, to determine if you have to turn it off.