31

我在新线程中创建处理程序时遇到问题。这是我的代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Runnable() {
        public void run() {
            Handler handler = new Handler();
        }
    }).start();
}

但它引发了一个错误!有人可以向我解释一下吗?非常感谢!

以下是我的错误的详细信息:

09-17 18:05:29.484: E/AndroidRuntime(810): FATAL EXCEPTION: Thread-75
09-17 18:05:29.484: E/AndroidRuntime(810): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
09-17 18:05:29.484: E/AndroidRuntime(810):  at android.os.Handler.<init>(Handler.java:197)
09-17 18:05:29.484: E/AndroidRuntime(810):  at android.os.Handler.<init>(Handler.java:111)
09-17 18:05:29.484: E/AndroidRuntime(810):  at com.example.handler.MainActivity$1.run(MainActivity.java:57)
09-17 18:05:29.484: E/AndroidRuntime(810):  at java.lang.Thread.run(Thread.java:856)
4

4 回答 4

89

你也可以使用HandlerThread这样的:

HandlerThread thread = new HandlerThread("MyHandlerThread");
thread.start();
Handler handler = new Handler(thread.getLooper());

HandlerThreads 与它们有Looper关联,因此这不会引发异常。

于 2013-09-17T18:29:24.650 回答
22

线程lifecycle在 run 方法返回后立即完成。但是由于您正在创建 a Handlerin this thread,因此 Handler 需要运行线程才能接收消息并处理它们。

所以为了发生这种情况,run 方法不应该退出。因此,您需要一个 Looper 来无限期地等待并处理到达 Handler 的消息。

new Thread(new Runnable() {
        public void run() {
            Looper.prepare();
            Handler handler = new Handler();
            Looper.loop();
        }
    }).start();
于 2013-09-17T18:14:41.323 回答
14

简短回答:因为您尝试附加处理程序的线程没有弯针。所以 Handler 类的构造函数抛出异常。您可以改用 HandlerThread 类,这只是 Android 框架提供的一个方便的类。

请阅读以下内容,了解幕后发生的事情。

让我们首先尝试单独讨论所有部分。

  1. 线:

一个。线程只是一个执行流。默认情况下,假设线程只执行其可运行(如果提供)或调用其运行方法。在调用 new Thread.start() 时。当 run 方法执行 run(){ ---- } 中编写的所有语句时,一个线程就会死掉并 Gc'd。

湾。Android中有一个Looper的概念。这基本上使线程成为阻塞线程。简单地说,它只是不会让线程死掉。它进入阻塞状态并等待更多消息再次恢复执行。

下面是您如何设置阻塞线程,即带有弯针的线程。

  new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        Looper.loop();
    }
}).start();

这里创建了一个线程,它不会在执行 Looper.loop() 语句后死掉。相反,它循环并进入阻塞状态。现在你一定会问阻塞状态是什么意思,线程是如何脱离阻塞状态的?我现在如何最终发布这个线程?这就是处理程序的用武之地

  1. 处理程序:

一个。它总是将自己附加到创建其实例的线程的 Looper 上。

湾。然后它处理它附加到的线程的那些消息。

将线程和处理程序放在一起。

new Thread(new Runnable() {
        public void run() {
            Looper.prepare();
            handler = new Handler();
            Looper.loop();
        }
    }).start();

一个。处理程序如何附加到这个新创建的线程。湾。该线程被设置为阻塞活套线程。所以这不会死。

现在,我们可以 1. 在这个处理程序上发送消息。2. 在这个处理程序上发布可运行文件。

它们都将在附加的线程上执行。

您可以选择扩展 Handler 类并实现方法 handleMessage(Message msg)。或者您只需在处理程序类的构造函数中提供 Handler.Callback 的实现。无论哪种方式,都将在附加线程上调用 handleMessage(Messages msg)。

要退出线程,您可以发送特定类型的消息类型,并在收到该消息后调用 Looper.myLooper().quit()

class LooperThread extends Thread {
   public Handler mHandler;

   public void run() {
      Looper.prepare();

      mHandler = new Handler() {
          public void handleMessage(Message msg) {
              // process incoming messages here
              if(msg.what == -1){
              Looper.myLooper().quit();
              }
          }
      };

      Looper.loop();
   }
}

我希望它有助于理解整体概念。

于 2017-01-03T22:12:03.750 回答
5

一个 Handler 需要在 Looper 线程中初始化,或者给它一个 Looper。

根据您想要做什么,您可以将线程设置为 Looper,如下所示:

new Thread(new Runnable() {
    public void run() {
        Looper.prepare();
        mHandler = new Handler();
        Looper.loop();
    }
}).start();

由于 Looper 在后台线程中,您无法更新 UI。你也可以从另一个线程给 Handler 一个 Looper——在这个例子中,Handler 可以用来更新 UI:

new Thread(new Runnable() {
    public void run() {
        Handler handler = new Handler(Looper.getMainLooper());
    }
}).start();
于 2013-09-17T18:15:11.903 回答