Android:为什么我不能在新线程中创建处理程序

时间:2022-01-20 02:13:39

I had a problem that I can't create a handler in new thread. This is my code:

我有一个问题,我不能在新线程中创建一个处理程序。这是我的代码:

    @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();
}

But it raised error! Who can explain to me. Thanks so much!

但它提出了错误!谁能向我解释。非常感谢!

Here is the detail of my error:

这是我的错误的详细信息:

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 个解决方案

#1


70  

You could also use a HandlerThread like this:

你也可以像这样使用HandlerThread:

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

HandlerThreads have a Looper associated with them, so this wouldn't throw an exception.

HandlerThreads有一个与它们相关联的Looper,所以这不会引发异常。

#2


16  

The Thread's lifecycle is finished right after run method returns. But since you are creating a Handler in this thread, the Handler needs the thread to be running for it to receive messages and process them.

Thread的生命周期在run方法返回后立即完成。但是由于您在此线程中创建了一个Handler,因此Handler需要运行该线程才能接收消息并处理它们。

So for this to happen, run method should not exit. Hence you need a Looper to wait indefinitely and process messages that arrive to Handler.

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

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

#3


8  

Short Answer: Because the thread you're trying to attach the Handler on, doesn't have a looper. And so the constructor of Handler class is throwing exception. You could have used a HandlerThread class instead, This is just a handy class provided by the Android framework.

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

Please read below for whats happening under the hood.

请阅读以下内容,了解引擎盖下发生的事情。

Lets first try to discuss all parts individually.

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

  1. Thread:

a. A thread is just a execution flow. A thread by default is suppose to just execute its runnable(if provided) or call its run method. Upon calling new Thread.start(). A thread just dies and Gc'd when the run method executes all the statement written inside the run(){ ---- }.

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

b. There is a concept of Looper in Android. Which basically makes the thread a blocking thread. Putting simply it just doesn't let the thread die. It goes in a blocking state and waiting for more messages to again resume its execution.

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

Below is how you'd setup a blocking thread i.e a thread with a looper.

下面是你如何设置一个阻塞线程,即一个带有looper的线程。

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

Here a thread is created which doesn't just die after executing the Looper.loop() statement. Instead it loops and goes in a blocking state. Now you must be asking what is the meaning of blocking state, how the thread will come out of the blocking state ? how do i finally release this thread now ? This is where Handler comes in

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

  1. Handler:

a. It always attaches itself to the Looper of the thread, on which its instance is created.

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

b. It then processes those messages of the thread it attaches to.

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

Putting together thread and handlers.

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

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

a. How the handler gets attached to this newly created thread. b. The thread is setup as a blocking looper thread. So this is not going to die.

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

now, we can 1. Send message on this handler. 2. Post runnable on this handler.

现在,我们可以1.在此处理程序上发送消息。 2.在此处理程序上发布runnable。

Both of them will be executed on the attached thread.

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

You have an option to either extend the Handler class and implement method handleMessage(Message msg). or you just provide implementation of the Handler.Callback in the constructor of the handler class. In either way the handleMessage(Messages msg) will be called on the attached thread.

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

To quit the thread you can send a specific type of message type, and upon receiving that message you'd just call Looper.myLooper().quit()

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

class LooperThread extends Thread { public Handler mHandler;

class LooperThread扩展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();
  }

}

I hope it helped understanding the overall concept.

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

#4


5  

A Handler needs to be initialised in a Looper thread, or have a Looper given to it.

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

Depending on what you want to do, you can set up your thread to be a Looper like so:

根据您的要求,您可以将线程设置为Looper,如下所示:

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

Since the Looper is in a background thread, you cannot update the UI. You could alternativly give the Handler a Looper from another thread - in this example, the Handler can be used to update the UI:

由于Looper位于后台线程中,因此无法更新UI。您可以替代地从另一个线程向Handler提供一个Looper - 在此示例中,Handler可用于更新UI:

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

#1


70  

You could also use a HandlerThread like this:

你也可以像这样使用HandlerThread:

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

HandlerThreads have a Looper associated with them, so this wouldn't throw an exception.

HandlerThreads有一个与它们相关联的Looper,所以这不会引发异常。

#2


16  

The Thread's lifecycle is finished right after run method returns. But since you are creating a Handler in this thread, the Handler needs the thread to be running for it to receive messages and process them.

Thread的生命周期在run方法返回后立即完成。但是由于您在此线程中创建了一个Handler,因此Handler需要运行该线程才能接收消息并处理它们。

So for this to happen, run method should not exit. Hence you need a Looper to wait indefinitely and process messages that arrive to Handler.

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

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

#3


8  

Short Answer: Because the thread you're trying to attach the Handler on, doesn't have a looper. And so the constructor of Handler class is throwing exception. You could have used a HandlerThread class instead, This is just a handy class provided by the Android framework.

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

Please read below for whats happening under the hood.

请阅读以下内容,了解引擎盖下发生的事情。

Lets first try to discuss all parts individually.

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

  1. Thread:

a. A thread is just a execution flow. A thread by default is suppose to just execute its runnable(if provided) or call its run method. Upon calling new Thread.start(). A thread just dies and Gc'd when the run method executes all the statement written inside the run(){ ---- }.

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

b. There is a concept of Looper in Android. Which basically makes the thread a blocking thread. Putting simply it just doesn't let the thread die. It goes in a blocking state and waiting for more messages to again resume its execution.

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

Below is how you'd setup a blocking thread i.e a thread with a looper.

下面是你如何设置一个阻塞线程,即一个带有looper的线程。

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

Here a thread is created which doesn't just die after executing the Looper.loop() statement. Instead it loops and goes in a blocking state. Now you must be asking what is the meaning of blocking state, how the thread will come out of the blocking state ? how do i finally release this thread now ? This is where Handler comes in

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

  1. Handler:

a. It always attaches itself to the Looper of the thread, on which its instance is created.

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

b. It then processes those messages of the thread it attaches to.

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

Putting together thread and handlers.

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

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

a. How the handler gets attached to this newly created thread. b. The thread is setup as a blocking looper thread. So this is not going to die.

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

now, we can 1. Send message on this handler. 2. Post runnable on this handler.

现在,我们可以1.在此处理程序上发送消息。 2.在此处理程序上发布runnable。

Both of them will be executed on the attached thread.

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

You have an option to either extend the Handler class and implement method handleMessage(Message msg). or you just provide implementation of the Handler.Callback in the constructor of the handler class. In either way the handleMessage(Messages msg) will be called on the attached thread.

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

To quit the thread you can send a specific type of message type, and upon receiving that message you'd just call Looper.myLooper().quit()

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

class LooperThread extends Thread { public Handler mHandler;

class LooperThread扩展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();
  }

}

I hope it helped understanding the overall concept.

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

#4


5  

A Handler needs to be initialised in a Looper thread, or have a Looper given to it.

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

Depending on what you want to do, you can set up your thread to be a Looper like so:

根据您的要求,您可以将线程设置为Looper,如下所示:

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

Since the Looper is in a background thread, you cannot update the UI. You could alternativly give the Handler a Looper from another thread - in this example, the Handler can be used to update the UI:

由于Looper位于后台线程中,因此无法更新UI。您可以替代地从另一个线程向Handler提供一个Looper - 在此示例中,Handler可用于更新UI:

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