Doing Background Work
Let’s say you have an app that requires some work to be done on a background thread, and then it needs to update the UI when the work completes. This work could be some database access or network communication.
The typical pattern in Android to do some background work is to use AsyncTask. In this example, my work is just going to be sleeping for a few seconds, and when finished, I’m going to show a message box to the user. Here is a complete implementation in a simple fragment:
Bugs
This may seem to work, but there is a major problem. If the user navigates away from your activity with the back button while the work is in progress, the app crashes because the fragment has been detached and the activity has been destroyed. The call to getActivity() returns null, resulting in NullPointerException. You could easily work around this problem by doing a null check:
That may be good enough for the simple cases. But it quickly becomes error-prone and tedious to always remember to handle detached fragments, especially when the app becomes more complex. And what if you really need to handle the result in the UI? What if you want to show the dialog immediately even if the user is now in a different activity?
Event Bus
Stepping back for a moment, the problem here is that the AsyncTask is now tied to the lifecycle of the Activity or Fragment where it was created. This is the cause of the issues because the task in reality lives independently from those things. So how can it be decoupled?
The event bus can solve these problems. Use the bus to pass events up to any activity (or any other object) that is interested in it. There are a few common event buses to choose from, such as Green Robot or Otto. I will use Otto for this example. FIrst include this in build.gradle:
Then define the bus and event:
Here’s how the event is published from the AsyncTask:
And the code to receive the event in the activity:
Notice how the data is passed through the event. The activity registers and unregisters itself to only receive the event when it is started. Therefore the dialog is guaranteed to be shown only when the user is running the activity, and you don’t need to remember any null checks or handle state management yourself. You can also handle the event and respond to it differently in different activities, and not have to check if the activity is null or destroyed.