我的程序在后台线程中执行一些网络活动。在开始之前,它会弹出一个进度对话框。该对话框在处理程序上被解除。这一切都很好,除了当对话框打开时屏幕方向发生变化(背景线程正在运行)。此时,应用程序要么崩溃,要么死锁,要么进入一个奇怪的阶段,在所有线程被杀死之前,应用程序根本无法工作。
我如何处理屏幕方向的变化优雅?
下面的示例代码大致匹配我的实际程序:
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();
}
};
}
栈:
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)
我已经尝试在onSaveInstanceState中取消进度对话框,但这只是防止了立即崩溃。背景线程仍在运行,UI处于部分绘制状态。需要在它重新开始工作之前杀死整个应用程序。
If you're struggling with detecting orientation change events of a dialog INDEPENDENT OF AN ACTIVITY REFERENCE, this method works excitingly well. I use this because I have my own dialog class that can be shown in multiple different Activities so I don't always know which Activity it's being shown in. With this method you don't need to change the AndroidManifest, worry about Activity references, and you don't need a custom dialog (as I have). You do need, however, a custom content view so you can detect the orientation changes using that particular view. Here's my example:
设置
public class MyContentView extends View{
public MyContentView(Context context){
super(context);
}
@Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
//DO SOMETHING HERE!! :D
}
}
实现1 -对话
Dialog dialog = new Dialog(context);
//set up dialog
dialog.setContentView(new MyContentView(context));
dialog.show();
实现2 - AlertDialog。构建器
AlertDialog.Builder builder = new AlertDialog.Builder(context);
//set up dialog builder
builder.setView(new MyContentView(context)); //Can use this method
builder.setCustomTitle(new MycontentView(context)); // or this method
builder.build().show();
实现3 - ProgressDialog / AlertDialog
ProgressDialog progress = new ProgressDialog(context);
//set up progress dialog
progress.setView(new MyContentView(context)); //Can use this method
progress.setCustomTitle(new MyContentView(context)); // or this method
progress.show();
编辑:谷歌工程师不推荐这种方法,正如Dianne Hackborn(又名hackbod)在StackOverflow的帖子中所描述的那样。查看这篇博客文章了解更多信息。
你必须把这个添加到manifest中的activity声明中:
android:configChanges="orientation|screenSize"
看起来是这样的
<activity android:label="@string/app_name"
android:configChanges="orientation|screenSize|keyboardHidden"
android:name=".your.package">
问题是,当配置发生更改时,系统将破坏活动。看到ConfigurationChanges。
所以把它放在配置文件中可以避免系统破坏你的活动。相反,它调用onConfigurationChanged(Configuration)方法。
我是这样做的:
package com.palewar;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class ThreadActivity extends Activity {
static ProgressDialog dialog;
private Thread downloadThread;
final static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
dialog.dismiss();
}
};
protected void onDestroy() {
super.onDestroy();
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
dialog = null;
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
downloadThread = (Thread) getLastNonConfigurationInstance();
if (downloadThread != null && downloadThread.isAlive()) {
dialog = ProgressDialog.show(ThreadActivity.this, "",
"Signing in...", false);
}
dialog = ProgressDialog.show(ThreadActivity.this, "",
"Signing in ...", false);
downloadThread = new MyThread();
downloadThread.start();
// processThread();
}
// Save the thread
@Override
public Object onRetainNonConfigurationInstance() {
return downloadThread;
}
static public class MyThread extends Thread {
@Override
public void run() {
try {
// Simulate a slow network
try {
new Thread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(0);
} finally {
}
}
}
}
你也可以试着让我知道它对你是否有效