1. ホーム
  2. アンドロイド

[解決済み】プログレスダイアログとバックグラウンドスレッドがアクティブなときに、画面の向きが変わるのをどう処理するか?

2022-03-23 06:56:14

質問

私のプログラムは、バックグラウンドスレッドでネットワークアクティビティを行います。開始する前に、進行状況ダイアログをポップアップします。このダイアログは、ハンドラで解除される。これはすべてうまくいくが、ダイアログが表示されている間(そしてバックグラウンド・スレッドが動いている間)、スクリーンの向きが変わったときだけは例外である。このとき、アプリはクラッシュするか、デッドロックになるか、すべてのスレッドが停止するまでアプリがまったく動作しない奇妙な状態になります。

画面の向きが変わるのをうまく処理するにはどうしたらいいですか?

以下のサンプルコードは、私の実際のプログラムの動作とほぼ一致しています。

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は部分的に描画された状態になっています。再び動作するようになる前に、アプリ全体を終了させる必要があります。

解決方法は?

向きを変えると、Androidは新しいViewを作成します。 背景スレッドが古いビューの状態を変更しようとしているため、クラッシュが発生していると思われます。 (背景スレッドがUIスレッド上にないため、問題が発生している可能性もあります)。

mHandlerをvolatileにして、向きが変わったときに更新することをお勧めします。