I’ve been thinking a lot about ways to improve the architecture (software) design of Android applications. I wanted to share an awesome design idea that I implemented in my NYC Find a Fountain App
First and foremost, Android apps that communicate with remote servers to get data will heavily rely on the use of Async Tasks for asynchronous communication. The use of these threads leans towards the Observer design pattern
Why Async Tasks?
If you try to communicate with a RESTful remote server, you’re not likely to get a quick response. In fact, once you get the response, you’re probably going to take a while to process the information (especially with poorly designed, humongous JSON feeds).
If your application doesn’t respond within 5 seconds, the operating system will issue a message to the user reading “Sorry, the application [your-app-name-here] is not responding! Force Close and leave a 1-star review??” This is not as bad as your program crashing, but the Application Not Responding (ANR) message means the programmer failed to optimize important code!
Async Tasks create background threads that keep the “Main User Interface (UI)” or activity free to perform/handle other user actions. Thus, async tasks prevent ANR messages!
Most people implement Async Tasks within the activity’s class:
public class MainActivity extends Activity{ //...The usual goes here: load up stuff, present menus, // handle user actions, etc... private class MyAsyncTask extends AsyncTask<String, Integer, Long>{ //Do async stuff here: doInBackground(), etc. }}
I hate this! The private class smack in the middle of your (already bloated enough) main activity’s class is just throwing readability out of the window.
Solution? Create a separate public class (e.g., MyAsyncTask within MyAsyncTask.java). Do all of your (heavy-lifting) processing in that class and all is well.
The new problem: how does the AsyncTask tell the main UI (MainActivity) that it’s all done with the processing? Hmmm…
One (bad but not so terrible) solution is to take in a Context for your AsyncTask. This is the context corresponding to the “MainActivity” activity. This context allows you to show Toasts and other cool stuff. If you need more detailed control over the MainActivity (for example, MyAsyncTask wants to call a function, foo()
, of MainActivity) then you’d consider a terrible solution of passing in (an indirect reference to) an activity (MainActivity) to the MyAsyncTask constructor:
Don’t do this! Ever. There’s a better way…
public class MyAsyncTask extends AsyncTask<String, Integer, Long>{ //Local reference to the main activity Activity mainActivity; public MyAsyncTask(Activity mainActivity){ this.mainActivity = mainActivity; } @Override protected Integer doInBackground(String... url){ //RESTful server fetching here... } @Override protected void onPostExecute(Integer result){ //We get here when we exit doInBackground(). //We should probably let the Main UI know we're done... //Let's just call the function that we want to trigger mainActivity.foo(); //NOOOOOOO! But it still works :/ }}
Now that you know never to do this, the problem remains! How do we tell the main UI that we’re done?
Observer Architecture
I like the idea of having the Main UI pass in a Handler to the Async Task (see the code below). The handler’s sole purpose is to be the messenger between our Async Task and the Main UI. When we’re done processing, initiate the sending of a Message to the handler saying “Hey Main UI, we’re done doing the hard stuff — go back to handling button clicks or whatever you do…”
Ultimately, the MainActivity “registers” itself with MyAsyncTask so that MyAsyncTask notifies MainActivity when things change (like processing finishing). MainActivity is “observing” the behavior or MyAsyncTask and wants its updates!
public class MyAsyncTask extends AsyncTask<String, Integer, Long>{ //Used to send messages back to the mainUI Handler mainUIHandler; public MyAsyncTask(Handler mainUIHandler){ this.mainUIHandler = mainUIHandler; } @Override protected Integer doInBackground(String... url){ //RESTful server fetching here... } @Override protected void onPostExecute(Integer result){ //We should probably let the Main UI know we're done... //Let's send a message! Messsage msg = Message.obtain(); msg.what = 1; //A public enumeration signifying success would be better. mainUIHandler.sendMessage(msg); }}
So What’s Next?
Well, now that the MyAsyncTask sent a message to MainActivity, MainActivity has to handle that message! This is done along the lines of:
In MainActivity.java
//Handles messages from the MyAsyncTaskHandler asyncHandler = new Handler(){ public void handleMessage(Message msg){ super.handleMessage(msg); //What did that async task say? switch (msg.what) { case 1: foo(); break; } }};
For completeness, you would send this handler to the Async Task like:
MyAsyncTask async = new MyAsyncTask(asyncHandler);async.execute("some URL");
Conclusion
Talk about loose coupling! 🙂 These two classes don’t even need each other to survive! The Async Task basically says “if you’re going to ask me to do something, make sure you leave a return address so that I know where to reply.” Of course, the “return address” is the Handler of the MainUI.
You can implement this handler-based communication with any classes that need to interact or notify the main UI. The examples that come to mind are Runnables that poll for certain events (e.g., like zooming or panning for Maps).
Happy coding!