Option #1: Don't have Android do the normal destroy/recreate cycle.
Add an android:configChanges attribute to your manifest for this
activity, and override onConfigurationChanged() to fix up your UI.
This keeps the same Activity instance, and so your AsyncTask should be
fairly happy. Here is a project that has this setup, though it does
not use an AsyncTask:
http://github.com/commonsguy/cw-android/tree/master/Rotation/RotationThree/
Option #2: Make the AsyncTask either a public top-level Java class
(not an inner class) or static inner class of the Activity. Manually
associate the Activity with the AsyncTask via a constructor parameter
in your AsyncTask instance. Associate the new Activity instance with
the AsyncTask after the rotation. You can see an example of this
technique here:
http://github.com/commonsguy/cw-android/tree/master/Rotation/RotationAsync/
Option #3: I think droid-fu may have some stuff related to this in
their library.
Personally, I'd use option #1.
--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://github.com/commonsguy
http://commonsware.com/blog | http://twitter.com/commonsguy
Android Training in London: http://skillsmatter.com/go/os-mobile-server
> --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-d...@googlegroups.com
> To unsubscribe from this group, send email to
> android-develop...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/android-developers?hl=en
>
--
Romain Guy
Android framework engineer
roma...@android.com
Note: please don't send private questions to me, as I don't have time
to provide private support. All such questions should be posted on
public forums, where I and others can see and answer them
Option #1 is a lot more intrusive. You lose the ability to
automatically switch layouts, drawables, etc. It might be fine now but
it might come back to bite you in the future. It should always be your
last resort. Saving and restoring an AsyncTask is not difficult.
Worst-case scenario:
Step #1: Take your UI setup that is in onCreate() and move it to a
separate method (e.g., setupViews())
Step #2: Call setupViews() from onCreate()
Step #3: Call setupViews() from onConfigurationChanged()
Done. ~4 lines of code. And it's the exact same code path that a
destroy/recreate will go down, so it's not like this adds unusual
performance overhead. There are certain circumstances where this may
not work (e.g., GLSurfaceView and a game), but you needed to do extra
work for those cases, anyway, to handle the destroy/recreate cycle.
> Saving and restoring an AsyncTask is not difficult.
No, it's not. The question is: is it reliable?
None of the AsyncTask documentation (class, article, etc.) covers this
case. It *appears* that you can write an AsyncTask such that
onPostExecute() or onProgressUpdate() will not be called in the middle
of the activity transition. However, that's not documented and hence
not guaranteed, and so while I'll describe a pattern that seems to
work, I personally don't trust it any further than I can throw your
large Froyo lawn ornament. If somebody could give us the recipe that
is guaranteed to work (i.e., works today, and is going to work in
Android 2.3/3.0/Turbo System 5000), that'd be *wonderful*.
Actually, I lied earlier. I'd choose Option #4:
Option #4: Don't do the AsyncTask in an activity. Use a Service and
have it do the AsyncTask, or use an IntentService if the sole purpose
of the service is to do stuff in a background thread. In particular,
an IntentService would be good for a download that you want to happen
regardless of what may go on with an activity (e.g., Android Market
downloading an APK), and so you don't need to worry about canceling
it.
What if that AsyncTask is downloading a file? Interrupting it,regardless of how nicely done, would be a bad thing wouldn't it?
Worst-case scenario:
Step #1: Take your UI setup that is in onCreate() and move it to a
separate method (e.g., setupViews())
Step #2: Call setupViews() from onCreate()
Step #3: Call setupViews() from onConfigurationChanged()
Done. ~4 lines of code. And it's the exact same code path that a
destroy/recreate will go down, so it's not like this adds unusual
performance overhead. There are certain circumstances where this may
not work (e.g., GLSurfaceView and a game), but you needed to do extra
work for those cases, anyway, to handle the destroy/recreate cycle.
> Saving and restoring an AsyncTask is not difficult.
No, it's not. The question is: is it reliable?
Option #4: Don't do the AsyncTask in an activity. Use a Service and
have it do the AsyncTask, or use an IntentService if the sole purpose
of the service is to do stuff in a background thread. In particular,
an IntentService would be good for a download that you want to happen
regardless of what may go on with an activity (e.g., Android Market
downloading an APK), and so you don't need to worry about canceling
it.
Oh, that is absolutely fantastic to hear.
I'd think it should be documented either on that method or here:
http://developer.android.com/guide/topics/resources/runtime-changes.html
Thankyouthankyouthankyou! :-)
Except you would have to make sure to destroy/recreate anything your
Activity might have a reference to that would need a new
configuration. Of course you can make it work, but you can easily
break your solution in subtle ways. The only reason to handle
orientation change yourself is if the destroy/create process is very
heavy (webpage loading for instance.)
> And it's the exact same code path that a
> destroy/recreate will go down, so it's not like this adds unusual
> performance overhead.
No it is not. You are keeping the same Activity instance and any state
associated with it. It is very different.
A Service runs on the UI thread by default, so some kind of mechanism to
push work to a background thread is still required. It can be a
WakefulIntentService, or, just as easily, an AsyncTask (I imagine it
takes care of acquiring a wake lock).
It seems to me (and that's just my opinion) that
onRetainNonConfigurationInstance / getLastNonConfigurationInstance is
probably the easiest way for small, one-at-a-time async tasks, where UI
feedback is supposed to be immediate.
These two methods use plain Java objects, don't require serialization or
parceling, so they are a good fit. The only issue is - switching UI
references. OnRetail... can null them out before storing the task in a
configuration object, and onStart / getLast... can store new UI
references in the task.
The task would also need to keep most recent progress state values, to
be displayed in the newly created activity.
--
Kostya Vasilyev -- WiFi Manager + pretty widget -- http://kmansoft.wordpress.com
Given Ms. Hackborn's explanation of the message flow, I would agree
with your assessment. Without that guarantee, though, I couldn't trust
this model.
> The task would also need to keep most recent progress state values, to be
> displayed in the newly created activity.
Actually, that shouldn't be needed. doInBackground() should be able to
just call publishProgress(). Those messages will just get queued up
until the new activity is ready.
--
http://github.com/commonsguy/cw-android/tree/master/Rotation/RotationAsync/
> --
> You received this message because you are subscribed to the Google
> Groups "Android Developers" group.
> To post to this group, send email to android-d...@googlegroups.com
> To unsubscribe from this group, send email to
> android-develop...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/android-developers?hl=en
>
--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://github.com/commonsguy
http://commonsware.com/blog | http://twitter.com/commonsguy
Android Training...At Your Office: http://commonsware.com/training
Oh, technically, it'll work, but the inner class will then *also* hold
an *implicit* reference to the old activity, which you don't want, as
you'll leak memory. Since you're not using the implicit reference --
replacing it with the explicit one -- you want to use a static inner
class.
--
Mark Murphy (a Commons Guy)
http://commonsware.com | http://github.com/commonsguy
--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-d...@googlegroups.com
To unsubscribe from this group, send email to
android-develop...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en