Android, AsyncTask, long running processes, and orientation changes - android

In the past, orientation changes and AsyncTask (and other long running background tasks) have not played well with each other. There's always been the issue of knowing what tasks (or threads) are still running in the newly created activity (from an orientation change), and what to do when a task ends while an Activity isn't attached.
Even with Fragments and the LoaderManager, this still seems to be a problem to me.
What is the preferred way these days, to manage arbitrary long running tasks and orientation changes? To know what tasks are running in the newly created activity. To make sure a task doesn't try to deliver it's information when an Activity isn't attached.
Thank you

In my program I just put
android:configChanges="orientation|keyboardHidden|keyboard"
in my activities in the manifest and be done with it. After 1 year I have had 0 problems.

As other post suggests, you can use android:configChanges=xxx.
BUT, this is not always desired. Android is designed to kill activity on configuration change, and create new one, and you may benefit from this in some situation, by providing alternative screen layout.
This makes sense for example in multi-pane app, where landscape orientation shows different views than portrait orientation.
So to return to your question: I didn't read about preferred way to handle long running operations, but from own experiences I'd suggest to store such task in persistent activity state (saved/restored in onRetainNonConfigurationInstance/onCreate), or using persistent Fragments.
If your Activity detects that some task is already running, it can give it chance to recreate dialog to show its progress.
And note: orienation change is not the only that can make your activity to be recreated. Be prepared for language change, docking, and other possibilities :) But still, orientation change is the most common one.

Its the same as it always has been: use a service. Broadcast events from your service and catch them in your activity (or some intermediate layer). Your activity can then choose what to do with those events based on its state.
This is a rather broad question.

Related

Starting singleTask activity every few seconds gives ANR in Android

In the app I have an activity which has launch mode as singleTask. There are number of use cases which pass through this activity and hence it's called number of times. On stress testing the app by running monkeyrunner script and calling this activity every few seconds causes ANR's.
I guess, the way it's designed where most of the use cases pass through this activity is not correct but I am not in a position to change this design.
Is there anyway ANR's can be suppressed? I mean, adding UI operations to event queue so that it doesn't block main UI thread and doesn't give ANR.
It is unclear from the question what your activity is (or should be) doing. Probably you need a service instead.
It is common to perform time-consuming operations in background threads and deliver the results to the UI thread.
You may use the classes Handler/Looper (it it easir to send Runnables rather than messages), or use an AsyncTask. The AsyncTask is nevertheless tricky, this is discussed here: Is AsyncTask really conceptually flawed or am I just missing something? . AFAIK Google tried to fix the typical bugs and made the new behavior incompatible with the old one (namely, I have seen some misbehavior on the newer Androids that may be explained by the assumption that since some version threads doing asynctask jobs get killed after the activity that started them goes out of the screen).
I can guess that singleTask is your way to fight the fact that an activity dies when the screen turns, and a new one comes. I suggest you use singletons (they survive screen rotation but do not survive a process restart, one more thing that sometimes happens in Android). (The user switches to an app like Camera, takes a big photo, returns back -- and the activity is restarted because Camera needed memory. Have seen this in practice, but that time I did not try to find out if the whole process was restarted.)
Anyway, please add logging telling you when your activity in entered and left, including onNewIntent() and other lifecycle functions (to be on the safe side, I recommend to print the thread names as well). Then you will probably see what is going on.

Rotating orientation during middle of web service call

I have a ListActivity that instantiates an AsyncTask, makes a call to a web service, and populates the ListView with the results.
How should I handle device rotation while the AsyncTask is still running? Should I cancel it, save off whatever data I need, and start a new one when the ListActivity is recreated? Does Android somehow already handle such a case?
It seems like what you require here is a service, not an Asynchtask - as you are running a long query that should persist and deliver it's results the same way regardless of orientation.
BTW, killing the Asynctask is NOT straightforward - best not to go there at all, but let a service run truly in the background.
Do you require that your ListActivity is recreated on orientation change? I would expect that your users would not want that - but would rather have the populating of the ListView carry on.
I have an app that does a series of HTTP GETs and POSTs within a string of AsyncTasks, without restarting the activity each time the orientation changes. All you need is a line similar to the following in your manifest.
android:configChanges="orientation"
See the docs at http://developer.android.com/guide/topics/manifest/activity-element.html
Torid's suggestion of overridding the config changed handler works in most situations. However, I've found that some manufacturer's devices still recreate the activity, even when you've done this (I've seen 1 HTC phone that does it so far).
The proper solution is CommonsWare's answer in the following link:
Background task, progress dialog, orientation change - is there any 100% working solution?

Android AsycTask and orentation changes

How should you handle AsyncTasks when configuration changes occur. I am accessing a ReSTful API through these tasks, and in the cases where I need to get data back and then display it to the user I am experiencing problems. If a configuration change occurs, like an orientation change then the Activity is not properly update. I believe that the AsyncTask is updating the old activity that has been destroyed. I have found a solution to this that requires creating a boolean in the Application class that keeps track of whether the AsyncTask I care about is still running, and then on rotations I cancel the listener then recreate it in the new Activity, then when the AsyncTask is done, the listener then displays the data to the user. This works well, but it requires lots of extras and requires a lot of management. Is there a way that the async task can be tied to the new instance of the activity. Or a way to abstract what I have done, so it does not require as much management for each task you have.
Thanks
Have a look at asynctask-screen-rotation. This implementation is working quite good for me.
I struggled with that a lot too, the best solution I found was to add android:configChanges="orientation" to your activity in the AndroidManifest.xml file. This will stop your activity from being destroyed and recreated when the orientation changes.

How to resume Android app where it was suspended (app not Activity)

How can I have my Android app resume where it last was, i.e. the Activity in view, etc.? If I am showing an Activity and press the Home button and then launch my app again it returns to the startup activity. I'd like it to work like an iPhone app where it suspends in place and resumes back to where the user last was.
Thank you.
You may need to set android:alwaysRetainTaskState="true" for your root activity in the manifest. From the documentation:
Whether or not the state of the task
that the activity is in will always be
maintained by the system — "true" if
it will be, and "false" if the system
is allowed to reset the task to its
initial state in certain situations.
The default value is "false". This
attribute is meaningful only for the
root activity of a task; it's ignored
for all other activities.
Normally,
the system clears a task (removes all
activities from the stack above the
root activity) in certain situations
when the user re-selects that task
from the home screen. Typically, this
is done if the user hasn't visited the
task for a certain amount of time,
such as 30 minutes.
However, when this
attribute is "true", users will always
return to the task in its last state,
regardless of how they get there. This
is useful, for example, in an
application like the web browser where
there is a lot of state (such as
multiple open tabs) that users would
not like to lose.
Be sure to save any information you want in your onPause method and check that information in onResume. This will let the app reload any information that was communicated. Some widgets keep state but others don't.
Additionally when an an activity is killed it's onSaveInstanceState method is called. So anything that needs to be stored to persistent memory should be done there.
Although i'm working with Mono for Android i had a similar question.
After some time researching on the web you can setup an Activity to be created using the singleton pattern. This will cause your app to only create one instance and - if you go back to the activity - this will load the last state of that activity for you.
You can do this by configuring the activity with the
android:alwaysRetainTaskState="true"
and the
android:launchMode="singleTask" //(preffered, or "singleInstance")
properties.
Singletask is the best since singleInstance is more suitable for single-activity-based apps.
In my case setting the launchmode made this baby rock as i wanted but i don't know if this is a Mono for Android or Android issue at the root..
Be aware: you will need to create an initialize method or something alike if you'd like to create a clean/fresh/new instance of the activity at some point.

Handle screen orientation changes when there are AsyncTasks running

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.
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.
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/
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.

Categories

Resources