开发者

Calling Looper more than once causes "sending message to a Handler on a dead thread"

I am using an Executor [fixed thread pool] with my own ThreadFactory that adds a Looper:

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

I am running a thread that makes network requests but if the network fails I would like a dialog message to be displayed to the user. This process is rather involving since it requires making AND displaying the request in the UI thread. I can wait for the user's response to the dialog by simply adding a Loop to the network thread and wait for a message to be send from the UI thread. This allows me to encapsulate the network requests in a while(tryAgain) thread. All works well except when the Looper.loop() method is called the second time (after a second network error dialog is displayed) and a message is sent by the dialog (in the UI thread) to the network thread's handler:

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(开发者_如何学Go);
                        }
                    });

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

In the AlertDialog instance is an 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();
    }
}

I've checked that the thread is still active with handler.getLooper().getThread().isAlive() which always returns true but it still gives me "sending message to a Handler on a dead thread". How is it that the Message/Handler has decided that the thread is dead? Shouldn't it rely on the .isAlive() method? In the end I am trying to avoid replicating the thread management build into the Android OS :-)


If you check the source in android/os/MessageQueue.java, you can see something like the following

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

So the message queue is basically unusable after Looper.quit() has been called the first time, as it enqueues a Message with a null target, which is the magical identifier for the message queue to stop enqueuing and appear "dead".


See http://code.google.com/p/android/issues/detail?id=20915, which is a possible root cause of the problem. It includes a workaround for the issue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜