我的程序在后台线程中执行一些网络活动。在开始之前,它会弹出一个进度对话框。该对话框在处理程序上被解除。这一切都很好,除了当对话框打开时屏幕方向发生变化(背景线程正在运行)。此时,应用程序要么崩溃,要么死锁,要么进入一个奇怪的阶段,在所有线程被杀死之前,应用程序根本无法工作。

我如何处理屏幕方向的变化优雅?

下面的示例代码大致匹配我的实际程序:

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处于部分绘制状态。需要在它重新开始工作之前杀死整个应用程序。


当前回答

这是一个非常古老的问题,出于某种原因出现在侧栏上。

如果后台任务只需要在活动处于前台时存活,“新的”解决方案是在保留的片段中托管后台线程(或者,最好是AsyncTask),如本开发指南和大量q&a中所述。

如果活动因配置更改而被销毁,则保留的片段将继续存在,但当活动在后台或后台堆栈中被销毁时则不存在。因此,如果onPause()中的isChangingConfigurations()为false,后台任务仍然应该被中断。

其他回答

当你改变方向时,Android会终止那个活动并创建新的活动。 我建议使用Rx java的retrofit。自动处理崩溃。

在改造调用时使用这些方法。

.subscribeOn (Schedulers.io ()) .observeOn (AndroidSchedulers.mainThread ())

看起来太“快速和肮脏”了,所以请指出缺点,但我发现有用的是……

在我的AsyncTask的onPostExecute方法中,我简单地包装了`。try/catch块中的进度对话框(带有空捕获)的Dismiss ',然后简单地忽略所引发的异常。似乎是错误的,但似乎没有不良影响(至少对于我随后所做的事情,这是启动另一个活动,将我的长时间运行查询的结果传递为一个额外)

将长任务移动到单独的类中。将其实现为主题-观察者模式。每当创建活动时,注册并在关闭时注销任务类。任务类可以使用AsyncTask。

我是一个新手在机器人,我尝试了这个,它是有效的。

public class loadTotalMemberByBranch extends AsyncTask<Void, Void,Void> {
        ProgressDialog progressDialog = new ProgressDialog(Login.this);
        int ranSucess=0;
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            progressDialog.setTitle("");    
            progressDialog.isIndeterminate();
            progressDialog.setCancelable(false);
            progressDialog.show();
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

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

            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            progressDialog.dismiss();
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
        }
}

这是一个非常古老的问题,出于某种原因出现在侧栏上。

如果后台任务只需要在活动处于前台时存活,“新的”解决方案是在保留的片段中托管后台线程(或者,最好是AsyncTask),如本开发指南和大量q&a中所述。

如果活动因配置更改而被销毁,则保留的片段将继续存在,但当活动在后台或后台堆栈中被销毁时则不存在。因此,如果onPause()中的isChangingConfigurations()为false,后台任务仍然应该被中断。