> For the complete documentation index, see [llms.txt](https://bookmarks.gitbook.io/android-bookmarks/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bookmarks.gitbook.io/android-bookmarks/android/chapter1/handler.md).

# Handler

## 一 Handler的作用

以下是文档对handler的介绍及其翻译

> A Handler allows you to send and process[`Message`](https://developer.android.google.cn/reference/android/os/Message.html)and Runnable objects associated with a thread's[`MessageQueue`](https://developer.android.google.cn/reference/android/os/MessageQueue.html). Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
>
> There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.

  通过handler可以将Message和Runnable对象发送并放置到期所在线程的MessageQueue队列当中。每一个Handler实例都会与单一的线程及其该线程的message队列关联。handler对象将会发送message或runnable对象到MessageQueue队列中等待被执行。

  需要使用Handler有两大主要的原因：

* 在将来的某个时间点调度处理消息和runnable对象；
* 将需要执行的操作放到其他线程之中，而不是自己的；

  调度处理消息是通过调用post(Runnable), postAtTime(Runnable, long),postDelayed(Runnable, long), sendEmptyMessage(int), sendMessage(Message),sendMessageAtTime(Message, long)和sendMessageDelayed(Message,long)等方法完成的。其中的post版本的方法可以让你将Runnable对象放进消息队列；sendMessage版本的方法可以让你将一个包含有bundle对象的消息对象放进消息队列，然后交由handleMessage(Message)方法处理。（这个需要你复写Handler的handleMessage方法）。

## 二 使用场景

  在实际开发中主线程是不允许做耗时的操作的，通常耗时的操作都需要在子线程中进行，但却又只能在主线程中更新UI。为了解决这个问题通常都需要使用到Handler，由于Handler运行在主线程中(UI线程中)，它与子线程可以通过Message对象来传递数据，这个时候，Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象，(里面包含数据),把这些消息放入主线程队列中，配合主线程进行更新UI。

  Handler中分发消息的一些方法：

```
post(Runnable)
postAtTime(Runnable，long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message，long)
sendMessageDelayed(Message，long)
```

  以上post类方法允许你排列一个Runnable对象到队列中，sendMessage类方法， 允许你安排一个带数据的Message对象到队列中，等待更新。

  以下的实例，功能为：通过线程修改界面TextView的内容：

```
public class MyHandlerActivity extends Activity { 
    TextView textView; 
    MyHandler myHandler; 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.mainLayout); 
        textView= (TextView ) findViewById(R.id.text_view); 
        myHandler = new MyHandler(); 
        // 当创建一个新的Handler实例时， 它会绑定到当前线程和消息的队列中，开始分发数据 
        // Handler有两个作用， 
        // 定时执行Message和Runnalbe 对象 
        // 让一个动作，在不同的线程中执行。 
        MyThread m = new MyThread(); 
        new Thread(m).start(); 
    } 

    /** 
    * 接受消息，处理消息 ，此Handler会与当前主线程一块运行 
    * */ 
    class MyHandler extends Handler { 
        public MyHandler() { 
        } 

        public MyHandler(Looper L) { 
            super(L); 
        } 

        // 子类必须重写此方法，接受数据 
        @Override 
        public void handleMessage(Message msg) { 
            super.handleMessage(msg); 
            // 此处可以更新UI 
            Bundle b = msg.getData(); 
            String data = b.getString("data"); 
            MyHandlerActivity.this.textView.setText(data); 
        } 
    } 

    class MyThread implements Runnable { 
        public void run() {  
            try { 
                Thread.sleep(10000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            Message msg = new Message(); 
            Bundle b = new Bundle();// 存放数据 
            b.putString("data"， "更新了"); 
            msg.setData(b); 
            MyHandlerActivity.this.myHandler.sendMessage(msg);
           // 向Handler发送消息，更新UI 
        } 
    } 
}
```

## 三 原理

  要理解handler的原理必须要了解下面几个要素:

* Looper: 一个线程可以产生一个Looper对象，由它来管理此线程里的MessageQueue(消息队列)。&#x20;
* 通过构造Handler对象来与Looper沟通，以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
* Message Queue(消息队列):用来存放线程放入的消息。
* 线程：UIthread 通常就是main thread，而Android启动程序时会替它建立一个MessageQueue。&#x20;
* ThreadLocal:用来保存某个线程中的数据

  **流程**

  **一 创建消息**

  每一个消息都需要被指定的Handler处理，通过Handler创建消息便可以完成此功能。Android消息机制中引入了消息池。Handler创建消息时首先查询消息池中是否有消息存在，如果有直接从消息池中取得，如果没有则重新初始化一个消息实例。使用消息池的好处是：消息不被使用时，并不作为垃圾回收，而是放入消息池，可供下次Handler创建消息时使用。消息池提高了消息对象的复用，减少系统垃圾回收的次数。消息的创建流程如图所示。

![](/files/-McN-BmTuVy4-_paUsgK)

#### 二 Handler发送消息

  UI主线程初始化第一个Handler时会通过ThreadLocal创建一个Looper，该Looper与UI主线程一一对应。使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。Looper初始化的时候会创建一个消息队列MessageQueue。至此，主线程、消息循环、消息队列之间的关系是1:1:1。 Handler、Looper、MessageQueue的初始化流程如图所示: ![](/files/-McN-BmUGS7W3UECobOF) Hander持有对UI主线程消息队列MessageQueue和消息循环Looper的引用，子线程可以通过Handler将消息发送到UI线程的消息队列MessageQueue中。

#### 三 Handler处理消息

  UI主线程通过Looper循环查询消息队列UI\_MQ，当发现有消息存在时会将消息从消息队列中取出。首先分析消息，通过消息的参数判断该消息对应的Handler，然后将消息分发到指定的Handler进行处理。 子线程通过Handler、Looper与UI主线程通信的流程如图所示。 ![](/files/-McN-BmVHswcybJL3AKX)
