1

ルーパーを追加する独自のThreadFactoryでExecutor[固定スレッドプール]を使用しています。

Handler HANDLER = new Handler();
Executor    THREADS = Executors.newFixedThreadPool(THREAD_POOL_SIZE, new ThreadFactory() {
    @Override public Thread newThread(Runnable runnable) {
        return new MyThread(new Runnable() {
            @Override public void run() {
                Looper.prepare();
                runnable.run();
            }
        });
    }
});

private static class MyHandler extends Handler {
    public boolean fail;
        public void handleMessage(Message msg) {
        switch(msg.what) {
            case 1:
                this.fail = msg.arg1 == 1;
                Looper.myLooper().quit();
                break;
            }
        }
    }
}

ネットワーク要求を行うスレッドを実行していますが、ネットワークに障害が発生した場合、ダイアログメッセージをユーザーに表示したいと思います。このプロセスは、UIスレッドでリクエストを作成して表示する必要があるため、かなり複雑です。ネットワークスレッドにループを追加し、UIスレッドからメッセージが送信されるのを待つだけで、ダイアログに対するユーザーの応答を待つことができます。これにより、ネットワーク要求をwhile(tryAgain)スレッドにカプセル化できます。Looper.loop()メソッドが2回目に呼び出され(2番目のネットワークエラーダイアログが表示された後)、ダイアログによって(UIスレッドで)メッセージがネットワークスレッドのハンドラーに送信される場合を除いて、すべてが正常に機能します。

THREADS.execute(new Runnable() {
    private MyHandler   myHandler   = new MyHandler();
    @Override public void run() {
        boolean tryAgain    = true;
        while(tryAgain) {
            try {
                switch(request) {
                    [Handle network requests]
                }
                tryAgain    = false;

            } catch(IOException e) {
                // The network is unavailable.  Ask the user if we should try again.
                e.printStackTrace();

            } finally {
                if(tryAgain) {
                    HANDLER.post(new Runnable() {   // The UI thread
                        @Override public void run() {
                            theAlertDialog.show();
                        }
                    });

                    // Wait for the results from the dialog which lives in the UI thread.
                    Looper.loop();

                    // At this point the dialog has informed us of our answer.
                    tryAgain = !myHandler.fail;
                }
            }
        }
    }
});

AlertDialogインスタンスには、OnClickListenerがあります。

DialogInterface.OnClickListener myOnclickListener = new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        Message msg = myHandler.obtainMessage(1);
        msg.setTarget(this.handler);
        msg.sendToTarget();
    }
}

スレッドがまだアクティブでhandler.getLooper().getThread().isAlive()あり、常にtrueを返すことを確認しましたが、それでも「デッドスレッドのハンドラーにメッセージを送信する」ことができます。メッセージ/ハンドラーがスレッドが停止しているとどのように判断したのですか?.isAlive()メソッドに依存するべきではありませんか?結局、私はスレッド管理ビルドをAndroidOSに複製することを避けようとしています:-)

4

2 に答える 2

6

android / os / MessageQueue.javaのソースを確認すると、次のようなものが表示されます。

  if (mQuiting) {
                RuntimeException e = new RuntimeException(
                    msg.target + " sending message to a Handler on a dead thread");
                Log.w("MessageQueue", e.getMessage(), e);
                return false;
            } else if (msg.target == null) {
                mQuiting = true;
            }
   }

したがって、メッセージキューは、Looper.quit()が最初に呼び出された後は基本的に使用できません。これは、メッセージキューがキューイングを停止して「デッド」に見えるようにするための魔法の識別子であるnullターゲットを使用してメッセージをエンキューするためです。

于 2010-11-23T10:16:34.393 に答える
1

http://code.google.com/p/android/issues/detail?id=20915を参照してください。これは、問題の根本的な原因である可能性があります。この問題の回避策が含まれています。

于 2011-10-18T21:08:07.590 に答える