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 Fragment
s. 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.
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.
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.
How to work with AsyncTask when screen rotates
i would suggest you to 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 tag in the AndroidManifest.xml, and been just fine.
android:configChanges="keyboardHidden|orientation"
source How to handle an AsyncTask during Screen Rotation?
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 retainedFragment
s. It solves the problem of retaining anAsyncTask
across a rotation change nicely. You basically need to host yourAsyncTask
inside aFragment
, callsetRetainInstance(true)
on theFragment
, and report theAsyncTask
's progress/results back to it'sActivity
through the retainedFragment
.
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.
Update UI from AsyncTask and handle properly screen rotate
You can run the AsyncTask
in a retained fragment.
public class TaskFragment extends Fragment {
private Callback mCallback;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallback = (Callback) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TaskFragment.Callback");
}
}
@Override
public void onDetach() {
super.onDetach();
mCallback = null;
}
public void execute(){
new CounterTask().execute();
}
public interface Callback {
void onTaskUpdate(String value);
}
public class CounterTask extends AsyncTask<Void, String, Void> {
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
publishProgress("Hello " + i);
} catch (Exception e) {
}
}
return null;
}
@Override
protected void onProgressUpdate(String... values) {
if(mCallback != null) {
String str = values[0];
mCallback.onTaskUpdate(str);
}
}
}
}
Then, implement the callback in your activity and add the fragment via the fragment manager.
public class SampleActivity extends Activity implements
TaskFragment.Callback {
private static final String TAG_TASK_FRAGMENT = "task_fragment";
private TaskFragment mTaskFragment;
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
text = new TextView(this);
text.setText("HELLO");
layout.addView(text);
if (savedInstanceState != null) {
text.setText(savedInstanceState.getString("text"));
}
setContentView(layout);
FragmentManager fm = getFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);
if(mTaskFragment == null){
mTaskFragment = new TaskFragment();
fm.beginTransaction()
.add(mTaskFragment, TAG_TASK_FRAGMENT)
.commit();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("text", text.getText().toString());
}
@Override
protected void onStart() {
super.onStart();
mTaskFragment.execute();
}
@Override
public void onTaskUpdate(String value) {
text.setText(value);
}
}
Related Topics
How Does One Use Glide to Download an Image into a Bitmap
Android:Loading an Image from the Web with Asynctask
Android: Bitmaps Loaded from Gallery Are Rotated in Imageview
Android Studio - Local Path Doesn't Exist
Reverse Engineering from an APK File to a Project
How to Startforeground() Without Showing Notification
How to Use the Simple Http Client in Android
Remove All Unused Resources from an Android Project
How to Deal with Install_Parse_Failed_Inconsistent_Certificates Without Uninstall
Use a Local Database in Xamarin
How to Add Sha-1 to Android Application
Passing Data Between Fragments to Activity
Show Alertdialog in Any Position of the Screen
How Did Google Manage to Do This? Slide Actionbar in Android Application
Android 4.3 Menu Item Showasaction="Always" Ignored