Handle Screen Orientation Changes When There Are Asynctasks Running

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.

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 screen orientation changes when there is an asyntask running with android 4.x

Solution 1 – Think twice if you really need an AsyncTask.

Solution 2 – Put the AsyncTask in a Fragment.

Solution 3 – Lock the screen orientation

Solution 4 – Prevent the Activity from being recreated.

Reference:http://androidresearch.wordpress.com/2013/05/10/dealing-with-asynctask-and-screen-orientation/

.....
the problem happens because the activity recreated when configuration changes,like orientation change etc.
You can lock the orientation change in the onPreExecuted() method of asyntask and unlock it in the onPostExecuted() method.

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.AsyncTask;
import android.widget.Button;
import android.widget.ProgressBar;

public class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
private Context context;
private ProgressBar progressBar;
private Button button;

public MyAsyncTask(ProgressBar progressBar,Context context,Button button){
this.context=context;
this.progressBar=progressBar;
this.button=button;

}

private void lockScreenOrientation() {
int currentOrientation =context.getResources().getConfiguration().orientation;
if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) {
((Activity)
context).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
((Activity) context).
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}

private void unlockScreenOrientation() {
((Activity) context).
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}

@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressBar.setMax(100);
button.setEnabled(false);
lockScreenOrientation();
}

@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub


for(int i=0;i<=100;i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
publishProgress(i);

}

return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
button.setEnabled(true);
unlockScreenOrientation();
}

}

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.

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

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.



Related Topics



Leave a reply



Submit