20

I've been bugged by this for a while. How do I properly handle screen orientation changes while I have a separate Thread / AsyncTask running? Currently, I have

android:configChanges="orientation|keyboard|keyboardHidden"

in my AndroidManifest.xml, but that is not really encouraged:

Note: Using this attribute should be avoided and used only as a last-resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.

Also, in the 2.3 emulator, it works when switching to landscape, but switching back to portrait fails.

Now, the reason why I use configChanges is because when the user switches orientation, I might have an AsyncTask running, doing some network traffic, and I don't want it stopped.

Is there any other way of doing this, or is there a way of fixing 2.3 to switch back to portrait?

I know about onRetainNonConfigurationInstance, but I'm not sure it would be a good idea to "save" the AsyncTask instance, mainly because the class that extends AsyncTask is not static (so it is tied to the Activity) -- and it needs to be, because in onPostExecute() it calls methods from the Activity instance.

N J
  • 27,217
  • 13
  • 76
  • 96
Felix
  • 88,392
  • 43
  • 149
  • 167

3 Answers3

7

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.

Flo
  • 27,355
  • 15
  • 87
  • 125
  • Very nice, much simpler than implementing a `Service`. Thanks. – Felix Jan 04 '11 at 09:09
  • @Flo I know this has been a while since the post but I am trying to do the same but I don't quite understand what you mean by "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." Any chance of an example? (I'm new to java and android1) – Bex Mar 28 '11 at 14:58
  • Sorry, I don't have a code example. But have a look at [the observer pattern](http://stackoverflow.com/questions/2483644/rosetta-stone-observer-pattern) I hope you will then understand what I mean with "register" (update()) and "notify" (addObserver()). – Flo Mar 28 '11 at 21:10
  • 2
    Ah in my former comment I mixed something up. "Register" would mean calling the addObserver() method and "notifying" would mean calling update(). – Flo Mar 29 '11 at 08:03
2

Take a look the droid-fu library BetterAsyncTask. It is meant to handle this exact case.

http://brainflush.wordpress.com/2009/11/16/introducing-droid-fu-for-android-betteractivity-betterservice-and-betterasynctask/

Falmarri
  • 47,727
  • 41
  • 151
  • 191
0

I already popped up similar question here.

Basically there is an example of how to pause/resume an AsynTask on device rotation. However it still does not fit for all cases (sometimes it is not possible to safely suspend the action, such as a new user creation on a remote server). For those "unsafe" cases you need to code somewhat I'd call a tricky "framework". You will see CommonsWare gives github links to the one.

Community
  • 1
  • 1
Vit Khudenko
  • 28,288
  • 10
  • 63
  • 91
  • So there's no way (easy) to keep the `AsyncTask` running while the `Activity` is being restarted. Bummer. However, I found out the not-switching-back-to-portrait is an emulator problem, since the settings app does the same thing. – Felix Jan 03 '11 at 13:58