2 xiaoxiaoaishang xiaoxiaoaishang 于 2012.09.11 14:00 提问

当进度对话框和后台线程活动的时候如何处理屏幕的方向的变化?

我的程序是在一个后台的线程里进行网络活动。在开始之前,它弹出一个进度对话框。这个对话框是处理器上被驳回的。除了当对话框出现的时候屏幕的方向发生变换(后台线程也跟随着发生变化),其他的都是正常的。在时,应用或者崩溃,有时候死锁,或者是当所有的线程都被杀死的时候进入到应用,否则一点都不起作用这样一个怪异的阶段。
我能怎样处理屏幕方向发生变化这个问题?
下面的示例代码大概就是我的真正的程序:

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

和:

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.

我试图在onSaveInstanceState上取消对话框的进度条,但是这只能防止立即崩溃。后台线程仍然在运行,而且这个用户界面有一部分是处于拉伸状态的。需要杀掉整个应用程序才会重新开始工作。

6个回答

Sueyexin
Sueyexin   2012.09.11 14:20
已采纳

当你转换方向的时候,android将会创建一个新的视图。你的程序可能会崩溃,因为你的后台线程是试图在一个老的视图上改变这个场景。(它可能也会有问题,因为你的后台的线程不是在UI的线程上)
我建议当方向改变的时候改变处理器并且进行更新。

suannai0314
suannai0314 最近一直在研究它,我可以判断,当你的应用改变了方向的时候你确实得到了一个新的控件。(你也得到了一个新的视图)如果你视图更新旧的视图,你将得到异常,因为这个老的视图有一个无效的应用环境(你的旧的控件)。你可以考虑引入myActivity.getApplicationContext()而不是一个控件的指针本身。
大约 5 年之前 回复
mansuifengqi
mansuifengqi 当方向改变的时候你应该在你的activity里得到onStart。本质上来说,你必须用老数据重新配置视图。所以我建议当你获得这个新的‘onStart’时,从进度条和重建创建的这个新视图获取更新的数值的数据。如果你也得到了一个新的控件,我不能随便的记得,但是通过文档应该能得到一些帮助。
大约 5 年之前 回复
liangchichexin
liangchichexin   2012.09.11 14:36

你必须在说明中把下边的代码加到控件的声明中:

android:configChanges="orientation"

就像这样

<activity android:label="@string/app_name" 
        android:configChanges="orientation|keyboardHidden" 
        android:name=".your.package">

当配置发生改变的时候,系统破坏了这个控件就出现了问题。具体看ConfigurationChanges.
所以把那个放在配置文件中就避免了系统破坏你的控件。相反的,它调用onConfigurationChanged(Configuration) 方法。

gouxiaojin
gouxiaojin   2012.09.11 14:48

我遇到了同样的问题,并且想到了一个解决方案,并不涉及使用ProgressDialog,但是我更快的得到了结果。
我所做的就是在它里边有一个进度条的布局。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ProgressBar
    android:id="@+id/progressImage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    />
</RelativeLayout>

然后在onCreate中执行以下操作

public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.progress);
}

然后在一个线程里做这个长任务,当任务完成后是一个可运行的状态时,你就可以把目录视图加入到你想要给这个控件做的真实的布局里。
例如:

mHandler.post(new Runnable(){

public void run() {
        setContentView(R.layout.my_layout);
    } 
});

我就是这么做的,并且我发现它运行的速度比显示ProgressDialog更快,而且在我看来,它的打扰比较少,并且看起来更好。
当然,如果你想要使用ProgressDialog,这个答案并不适合你。

yizhenbeifeng
yizhenbeifeng   2012.09.11 15:03

我是这样做的

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;
        }

    }

    /** 当activity第一次创建的时候调用*/
    @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 {

            }
        }
    }

}

我是这样做的,并且它也起作用,你可以试试,然后告诉我它是否能解决你的问题。

u010646502
u010646502   2016.04.20 16:55

方向改变的时候改变处理器并且进行更新

u1254z62
u1254z62   2017.01.03 18:12

方向改变的时候改变处理器并且进行更新

Csdn user default icon
上传中...
上传图片
插入图片