Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Handling Background and Asynchronous Tasks in A...

Handling Background and Asynchronous Tasks in Android

Talk about designing code for a complex background task on an Android application.

Ari Lacenski

May 11, 2015
Tweet

More Decks by Ari Lacenski

Other Decks in Programming

Transcript

  1. Applications run with at least one execution thread: the main

    thread, or UI thread. The runtime environment manages the UI thread, so you don’t have to. Long-running operations of any length can block the UI thread, and some kinds of operations are just not allowed. If you’re not drawing pixels or handling user interaction, your code may block those two responsibilities. Android Threads
  2. — Anders Göransson, Efficient Android Threading "Each thread allocates a

    private memory area that is mainly used to store method local variables and parameters during the execution of [the thread]. The private memory area is allocated when the thread is created and deallocated once the thread terminates." There is a small delay each time execution jumps from one thread to another.
  3. AsyncTask Convenient way to offload work from the main thread

    Runs your code in doInBackground() on new thread Runs your code in onPostExecute() as a callback on UI thread
  4. AsyncTask runs on a Handler // AsyncTask.java! private static class

    InternalHandler extends Handler {! @Override! public void handleMessage(Message msg) {! AsyncTaskResult result = (AsyncTaskResult) msg.obj;! switch (msg.what) {! case MESSAGE_POST_RESULT:! // There is only one result! result.mTask.finish(result.mData[0]);! break;! case MESSAGE_POST_PROGRESS:! result.mTask.onProgressUpdate(result.mData);! break;! }! }! }
  5. new AsyncTask<Void, Void, Boolean>() {! protected Boolean doInBackground(Void... params) {!

    doOneThing();! return null;! }! protected void onPostExecute(Boolean result) {! AsyncTask doAnotherThing = ! new AsyncTask<Void, Void, Boolean>() {! protected Boolean doInBackground(Void... params) {! doYetAnotherThing();! return null;! }! private void doYetAnotherThing() {}! };! doAnotherThing.execute();! }! private void doOneThing() {}! }.execute(); I know, I’ll just write a nested AsyncTask…
  6. IntentService IntentService starts and shuts down its own thread for

    you. You start it with an Intent, and you can access that Intent from within IntentService.onHandleIntent().
  7. Service Signaling between Activity and Service Activity ResultReceiver rr =

    new ResultReceiver() {! @Override! onReceiveResult() {! // do stuff!! }! }! // add rr to extras! startService(myServiceIntent) onHandleIntent(Intent i) {! ResultReceiver rr =! i.getExtras().get(RR_KEY) ! (assigned from bundle)! ! rr.send(Activity.RESULT_OK! successData);! } Intent bundle https://guides.codepath.com/android/Starting-Background-Services
  8. Designing task communication 1. Task should run on a background

    thread. 2. Task should be able to signal success and failure back to the UI thread. 3. Task module should run subtasks in sequence. 4. Asynchronous subtasks should trigger the next task step when they are finished. 5. Task code should be easy for developers to understand.
  9. 1. Obtain an auth token with a network request 2.

    Fetch user account with a network request 3. Create a new local DB 4. Sync (push) remote DB with new local DB 5. Cancel login if syncing the remote DB fails 6. Catch exceptions 7. Remove old scheduled alarms 8. Copy a few settings from old to new DB 9. Stop replication on the old database 10. Delete the old database 11. Set the new database as the active one 12. Sync (push) the new database 13. Show a success response to the user
 (but only when syncing is done!) Building a login task
  10. 1. Obtain an auth token with a network request 2.

    Fetch user account with a network request 3. Create a new local DB 4. Sync (push) remote DB with new local DB 5. Cancel login if syncing the remote DB fails 6. Catch exceptions 7. Remove old scheduled alarms 8. Copy a few settings from old to new DB 9. Stop replication on the old database 10. Delete the old database 11. Set the new database as the active one 12. Sync (push) the new database 13. Show a success response to the user
 (but only when syncing is done!)
  11. Setting up a logged-in state Make a network call for

    a login token OK Make a network call for the user account OK Sync local DB with remote data OK
  12. // MyTaskModule.java! private static class LoginHandler extends Handler {! MyCallback

    callback;! ! @Override! public void handleMessage(Message msg) {! switch (msg.what) {! case QUIT:! callback.onFailure();! break;! case STARTED:! doStuff();! send(obtainMessage(NEXT_STEP));! break;! case NEXT_STEP:! callback.onSuccess();! break;! }! }! } Messaging Handler
  13. Activity to Service to module Activity Service implements MyTaskModule.MyCallback MyTaskModule

    public interface MyCallback() {! public void onSuccess();! public void onFailure();! }! ! // rest of task implementation! public void start(MyCallback callback) {! // call onSuccess or! // onFailure here!! } public void onSuccess() {! rr.send(RESULT_OK);! }! ! public void onFailure() {! rr.send(RESULT_CANCEL);! }! ! myTaskModule.start(this); Pass the Service into the task module as a callback implementation. start
  14. Putting it all together Activity Service Task module Task Handler

    Defines the ResultReceiver Starts a background thread Defines task components Runs task components Starts the Service Starts the task module Starts executing task Shows task outcome in UI Binds itself to the task module Communicates to the Service Communicates to the Activity Defines service communication Stops the thread
  15. Ari Lacenski http://gradlewhy.ghost.io [email protected] @tensory on Twitter and Github 1.

    https://guides.codepath.com/android 2. Efficient Android Threading by Anders Göransson 3. http://developer.android.com/guide/components/ processes-and-threads.html 4. https://developer.android.com/training/multiple- threads/index.html Further reading