Best Practice: Asynctask During Orientation Change

Best practice: AsyncTask during orientation change

Do NOT use android:configChanges to address this issue. This is very bad practice.

Do NOT use Activity#onRetainNonConfigurationInstance() either. This is less modular and not well-suited for Fragment-based applications.

You can read my article describing how to handle configuration changes using retained Fragments. It solves the problem of retaining an AsyncTask across a rotation change nicely. You basically need to host your AsyncTask inside a Fragment, call setRetainInstance(true) on the Fragment, and report the AsyncTask's progress/results back to it's Activity through the retained Fragment.

How to handle a running AsyncTask during orientation/configuration change?

According to this page : http://developer.android.com/guide/topics/manifest/activity-element.html#config, if your application targets API level 13 or higher, you should use android:configChanges="orientation|screenSize" to catch the screen rotation into the onConfigurationChanged() method.

By doing this, the onPause and onResume methods are not called, so your TextView will keep its value. And in my mind, it won't stop the running AsyncTask. If it does, try to recall it in the onConfigurationChanged method.

Handle orientation change with running AsyncTask

Here are my tips:

  • Do not use android:configChanges to address this issue.

  • Do not use Activity#onRetainNonConfigurationInstance() to address it either (as this approach is deprecated).

  • Instead, use a retained worker Fragment. I've recently posted an article describing how to handle configuration changes using retained Fragments. It solves the problem of retaining an AsyncTask across a rotation change nicely. You basically need to host your AsyncTask inside a Fragment, call setRetainInstance(true) on the Fragment, and report the AsyncTask's progress/results back to it's Activity through the retained Fragment.

How to handle an AsyncTask during Screen Rotation?

My first suggestion would be to make sure you actually need your activity to be reset on a screen rotation (the default behavior). Every time I've had issues with rotation I've added this attribute to my <activity> tag in the AndroidManifest.xml, and been just fine.

android:configChanges="keyboardHidden|orientation"

It looks weird, but what it does it hand off to your onConfigurationChanged() method, if you don't supply one it just does nothing other than re-measure the layout, which seems to be a perfectly adequate way of handling the rotate most of the time.

Best practice to handle orientation change: Android


Some summaries

There are several methods mentioned above that are good practices but I thought I might sum them up with short explanations. Below are some of the most popular libraries being used currently for http networking, asynchronous work / threading, and caching.

My current project (just preferences)

I personally am currently using Otto, Loaders, Volley, Ormlite, and a network stack based on Apache and Services. I do hope to replace, the network stack at some point with either Volley, Retrofit, and maybe eventually Robospice.

I personally very much like Otto and Volley


RoboSpice (Modular)

  • https://github.com/octo-online/robospice
  • http://www.youtube.com/watch?v=ONaD1mB8r-A
  • a plugin / modular approach to long-running tasks
  • this is like the "swiss-army-knife" of libraries, but you need to know what each tool does.
  • Handles REST calls
  • persists data through orientation and other changes
  • can handle disk and memory caching )
  • works with various HTTP libraries and persistence libraries (Gson, Jackson, Spring, OkHttp, and many of the below libraries)
  • beta for Ormlite support, I think

Retrofit (REST)

  • https://github.com/square/retrofit
  • Annotation library to make REST very easy. Works with Robospice.

Volley (Networking data & Images)

  • https://android.googlesource.com/platform/frameworks/volley
  • https://developers.google.com/events/io/sessions/325304728
  • This is the networking code that runs the Google Play Store
  • Fast, reliable
  • Handles most caching for you with some sensible defaults
  • very easy to use
  • built specifically for very fast image, json, etc loading
  • Handles all threading for you.

Picasso (images)

  • https://github.com/square/picasso
  • Http library for loading images
  • fast
  • very easy to use

Loaders (Android)

  • well supported
  • persist through orientation change and save/load of fragment state
  • can be difficult to get right
  • no caching

AsyncTask (Android)

  • simple way for background work from the UI thread
  • must be canceled and be careful about tasks that return after an activity or fragment is torn down.

Otto (event bus)

  • https://github.com/square/otto
  • Event bus that makes a-sync work between components and fragments easy
  • Very powerful @Produce ability retains the last event and can produce it on demand for any new interested subscribers to the bus

Headless Fragments (?)

  • I personally have never seen this used other than Vogella's tutorials, so I'm not sure on this one.

Service (Android)

  • The old school way
  • ultimate control, you must do everything yourself
  • usually used with Appache or HURL client and
  • pass Parcels around via Intents

Android Fragments. Retaining an AsyncTask during screen rotation or configuration change

Fragments can actually make this a lot easier. Just use the method Fragment.setRetainInstance(boolean) to have your fragment instance retained across configuration changes. Note that this is the recommended replacement for Activity.onRetainnonConfigurationInstance() in the docs.

If for some reason you really don't want to use a retained fragment, there are other approaches you can take. Note that each fragment has a unique identifier returned by Fragment.getId(). You can also find out if a fragment is being torn down for a config change through Fragment.getActivity().isChangingConfigurations(). So, at the point where you would decide to stop your AsyncTask (in onStop() or onDestroy() most likely), you could for example check if the configuration is changing and if so stick it in a static SparseArray under the fragment's identifier, and then in your onCreate() or onStart() look to see if you have an AsyncTask in the sparse array available.

Handle screen orientation changes when there are AsyncTasks running

I had a similar problem to your and worked around it by implementing the AsyncTask as part of a class which inherits from Application class. An Application class is available all the life time of the application So you don't have to worry about your AsyncTask getting interrupted unless the whole application will be killed.

To get notified when the task has finished the Activity has to implement a interface which it uses to register itself to the Application class.

When your application is destroyed because of the screen rotation you can unregister your Activity from the Application class and re-register it when it is recreated. If the task finishes between destruction and recreation the result of the operation can be stored in the Application class meanwhile so the Activity can check whether the task is still running or whether the result is already available when it is recreated.

Another advantage is that you have direct access to the applications context because the Application class is a sub class of the Context class.

Handle orientation change with running AsyncTask

Here are my tips:

  • Do not use android:configChanges to address this issue.

  • Do not use Activity#onRetainNonConfigurationInstance() to address it either (as this approach is deprecated).

  • Instead, use a retained worker Fragment. I've recently posted an article describing how to handle configuration changes using retained Fragments. It solves the problem of retaining an AsyncTask across a rotation change nicely. You basically need to host your AsyncTask inside a Fragment, call setRetainInstance(true) on the Fragment, and report the AsyncTask's progress/results back to it's Activity through the retained Fragment.

How prevent rotation until AsyncTask is not ended

Its not possible to pause screen rotation. You can only stop it entirely using configChanges in your activity manifest entry (but that is bad practice). What you should do is to put your async task in retained fragment. Until recently you could use Activity.getLastNonConfigurationInstance and Activity.onRetainNonConfigurationInstance to keep reference to AsyncTask between Activity being destroyed and recreated but now its deprecated. But you can still use it.

read here for more information: http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance()

Also:

if I try to rotate the device during AsincTask the App crashes

this actually should not happen, it is possible that you keep reference to your Activity in AsyncTask and use it after it is destroyed. This is called reference leak. To avoid it keep reference to your Activity in WeakReference, also if your AsyncTask is an inner class, then make it static. If it is possible, destroy your asynctask in Activity.onDestroy - by cancelling it, in async task check if it is cancelled and stop processing. If you use it to download things then consider retained fragment or IntentService.



Related Topics



Leave a reply



Submit