How to handle screen orientation change when progress dialog and background thread active?
- by Heikki Toivonen
My program does some network activity in a background thread. Before starting, it pops up a progress dialog. The dialog is dismissed on the handler. This all works fine, except when screen orientation changes while the dialog is up (and the background thread is going). At this point the app either crashes, or deadlocks, or gets into a weird stage where the app does not work at all until all the threads have been killed.
How can I handle the screen orientation change gracefully?
The sample code below matches roughly what my real program does:
public class MyAct extends Activity implements Runnable {
public ProgressDialog mProgress;
// UI has a button that when pressed calls send
public void send() {
mProgress = ProgressDialog.show(this, "Please wait",
"Please wait",
true, true);
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Thread.sleep(10000);
Message msg = new Message();
mHandler.sendMessage(msg);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mProgress.dismiss();
}
};
}
Stack:
E/WindowManager( 244): Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): android.view.WindowLeaked: Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): at android.view.ViewRoot.<init>(ViewRoot.java:178)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:147)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:90)
E/WindowManager( 244): at android.view.Window$LocalWindowManager.addView(Window.java:393)
E/WindowManager( 244): at android.app.Dialog.show(Dialog.java:212)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:103)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:91)
E/WindowManager( 244): at MyAct.send(MyAct.java:294)
E/WindowManager( 244): at MyAct$4.onClick(MyAct.java:174)
E/WindowManager( 244): at android.view.View.performClick(View.java:2129)
E/WindowManager( 244): at android.view.View.onTouchEvent(View.java:3543)
E/WindowManager( 244): at android.widget.TextView.onTouchEvent(TextView.java:4664)
E/WindowManager( 244): at android.view.View.dispatchTouchEvent(View.java:3198)
E/WindowManager( 244): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:857)
E/WindowManager( 244): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:857)
E/WindowManager( 244): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:857)
E/WindowManager( 244): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:857)
E/WindowManager( 244): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:857)
E/WindowManager( 244): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1593)
E/WindowManager( 244): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1089)
E/WindowManager( 244): at android.app.Activity.dispatchTouchEvent(Activity.java:1871)
E/WindowManager( 244): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1577)
E/WindowManager( 244): at android.view.ViewRoot.handleMessage(ViewRoot.java:1140)
E/WindowManager( 244): at android.os.Handler.dispatchMessage(Handler.java:88)
E/WindowManager( 244): at android.os.Looper.loop(Looper.java:123)
E/WindowManager( 244): at android.app.ActivityThread.main(ActivityThread.java:3739)
E/WindowManager( 244): at java.lang.reflect.Method.invokeNative(Native Method)
E/WindowManager( 244): at java.lang.reflect.Method.invoke(Method.java:515)
E/WindowManager( 244): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
E/WindowManager( 244): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
E/WindowManager( 244): at dalvik.system.NativeStart.main(Native Method)
and:
W/dalvikvm( 244): threadid=3: thread exiting with uncaught exception (group=0x4000fe68)
E/AndroidRuntime( 244): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 244): java.lang.IllegalArgumentException: View not attached to window manager
E/AndroidRuntime( 244): at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:331)
E/AndroidRuntime( 244): at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:200)
E/AndroidRuntime( 244): at android.view.Window$LocalWindowManager.removeView(Window.java:401)
E/AndroidRuntime( 244): at android.app.Dialog.dismissDialog(Dialog.java:249)
E/AndroidRuntime( 244): at android.app.Dialog.access$000(Dialog.java:59)
E/AndroidRuntime( 244): at android.app.Dialog$1.run(Dialog.java:93)
E/AndroidRuntime( 244): at android.app.Dialog.dismiss(Dialog.java:233)
E/AndroidRuntime( 244): at MyAct$1.handleMessage(MyAct.java:321)
E/AndroidRuntime( 244): at android.os.Handler.dispatchMessage(Handler.java:88)
E/AndroidRuntime( 244): at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 244): at android.app.ActivityThread.main(ActivityThread.java:3739)
E/AndroidRuntime( 244): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 244): at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime( 244): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
E/AndroidRuntime( 244): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
E/AndroidRuntime( 244): at dalvik.system.NativeStart.main(Native Method)
I/Process ( 46): Sending signal. PID: 244 SIG: 3
I/dalvikvm( 244): threadid=7: reacting to signal 3
I/dalvikvm( 244): Wrote stack trace to '/data/anr/traces.txt'
I/Process ( 244): Sending signal. PID: 244 SIG: 9
I/ActivityManager( 46): Process MyAct (pid 244) has died.
I have tried to dismiss the progress dialog in onSaveInstanceState, but that just prevents an immediate crash. The background thread is still going, and the UI is in partially drawn state. Need to kill the whole app before it starts working again.