Design Patterns: iOS and Android – Dispatch Queues and AsyncTask
For the past few weeks, I’ve been learning Android and porting one of my iOS apps to the platform. While there are many differences between the two platforms, it’s also kind of interesting to see common design patterns between them. I figured I should write up the common design patterns that I notice and maybe help out some iOS developers who are also learning Android like me.
Today I’ll look at doing asynchronous tasks in each platform. While there are many ways of doing this in both platforms, I’ll take a look at Dispatch Queues for iOS and AsyncTask in Android, since that’s what I’ve been using lately.
In iOS, you can use the dispatch_async
call to run code on a background dispatch queue. Say we get an NSArray of JSON objects and want to save them to a Core Data store. We can call dispatch_async on a dispatch queue, process all of the objects and then update the UI by using dispatch_async again on the main queue:
NSArray *stuff = [NSJSONSerialization JSONObjectWithData:responseData ...];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//if using core data, set up a new NSManagedObjectContext for this background thread
for (id *obj in stuff) {
//do time consuming work here
}
dispatch_async(dispatch_get_main_queue(), ^(void){
//do stuff on UI, send notifications!
[[NSNotificationCenter defaultCenter] postNotificationName:@"stuffHappenedNotification" object:nil];
});
});
In Android, performing a lightweight asynchronous task requires you to subclass AsyncTask. I guess I’m using the term “lightweight” loosely because creating a subclass just to do something asynchronously seems a bit heavy, but at least you get to reuse your code!
You must define three generic types which describe what the input is (in this example, a String), the progress type (an Integer) and a result (a Boolean).
private class SomeBackgroundTask extends AsyncTask<String, Integer, Boolean> {
@Override
protected void onPreExecute() {
//this is called first; you can use this to set up UI elements like a progress bar
}
@Override
protected Boolean doInBackground(String... response) {
JSONTokener tokenizer = new JSONTokener(response[0]);
JSONArray stuff = new JSONArray(tokenizer);
for(int i = 0; i < root.length(); i++){
//do time consuming work here
//the return type is Boolean, but it could really be anything we want
//we can call publishProgress(Progress...) here to call the onProgressUpdate method below on the ui thread
}
return Boolean.TRUE;
}
@Override
protected void onPostExecute(Boolean aBoolean) {
//this is called with the result of doInBackground as a parameter. this method is also called on the ui thread
}
@Override
protected void onProgressUpdate(Integer... progress) {
//this is called from doInBackground with the function "publishProgress(Progress...)"
//I use this method to send a local broadcast intent back to my main activity
}
}
Once you have that AsyncTask set up, you can call
new SomeBackgroundTask().execute(yourString);
to run your asynchronous task. One tricky thing to remember is that execute takes a list of objects and sends it to doInBackground as an array. I’m not BFF with Java so the syntax threw me a bit, but apparently it’s using a feature called varargs that’s been in Java for a while now.
That’s all for today. I hope this blog post was useful. I certainly found it useful, since I had to do some research to really understand what the heck I was writing about. I’ll probably write about UITableViewDelegate/Datasource vs. ListAdapter next, unless there’s something else that seems more timely.