【Android】报错:Can't create handler inside thread that has not called Looper.prepare()

Toast.makeText(mContext, "msg", Toast.LENGTH_SHORT).show();

在子线程里创建 Toast 时出现报错:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare().
在没有调用 Looper.prepare() 的线程里,无法创建 handler

原因是修改 UI 需要在主线程里。

1. Thread

因为线程需要 Looper 来循环处理消息,但是子线程中默认是没有 Looper 的,查看一下 Looper 的源码,类注释如下:

/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * 

Most interaction with a message loop is through the * {@link Handler} class. * *

This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * *

  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }
*/

注释里说明了线程默认是没有 Looper 的,需要在线程里手动调用 Looper.prepare() 来创建 Looper,并且调用 Looper.loop() 来遍历消息。并且还附带了一个例子。

所以我们直接按照官方给的例子调用即可:

new Thread(new Runnable() {
    @Override
    public void run() {
        Looper.prepare();
        Toast.makeText(mContext, "msg", Toast.LENGTH_SHORT).show();
        Looper.loop();
    }
}).start();

2. Handler

如果直接在子线程里创建 new Handler(),也会报同样的错误,因为子线程默认是没有 Looper 的。
可以使用 public Handler(Looper looper) 构造方法创建 Handler,传递主线程的 Looper

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(mContext, "msg", Toast.LENGTH_SHORT).show();
    }
});

3. runOnUiThread

如果是在 Activity 里,可以使用 runOnUiThread

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(mContext, "msg", Toast.LENGTH_SHORT).show();
    }
});

或者

if (mContext instanceof Activity) {
    ((Activity) mContext).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(mContext, "msg", Toast.LENGTH_SHORT).show();
        }
    });

参考

  1. Can’t create handler inside thread that has not called Looper.prepare()
  2. Android 子线程创建handler
  3. Android 带你彻底理解跨线程通信之Handler机制

你可能感兴趣的:(Android,Android,bug)