简单理解Handler

Published: by Creative Commons Licence (Last updated: )

简单理解 Handler

Handler、Looper和Message queue都位于同一个线程中,只是在其他线程中引用Handler(使用该引用来获取和发送message)。

Handler中存在一个Looper引用, Message中存在一个Handler引用。 然后下面是关键(要有此概念,有助于理解后面的操作):一个Looper可以被多个Handler引用,一个Handler也可以被多个Message引用。

在Handler创建时就会自动关联本线程中的Looper。如果线程中没有Looper对象,则会报错。

Message对象经常需要定义的三个变量:

  • What:用来描述消息(区分该类消息)
  • obj:随消息发送的用户指定对象。
  • target:处理消息的Handler。Message的目标是一个Handler的实例。

Handler不仅仅是处理Message的目标(target)也是创建和发布Message的接口。也就是说Handler不仅处理Message,也可以创建Message和发布Message。

Handle用来获取Message的方法:Handler.obtainMessage() 该方法会从公共循环池里获取消息。因此相比创建新message实例更有效率。

一旦取得Message,我们就调用Message的 sendToTarget() 方法将其发送给它的 Handler 。紧接着Handler会将Message放置在Looper消息队列的尾部。

下面列举一个使用Handler的示例

主线程与HandlerThread线程的交互。双方都引用了对方的handler。

+-----------------+                              +--+------------+--+
|                 |     给我下载图片               |  | handler    |  |
|      主线程      +----------------------------> |  +------------+  |
|                 |                              |                  |
|  +----------+   | <----------------------------+  HandlerThread   |
|  | handler  |   |  图片下载完成,请更新视图       |                  |
+--+----------+---+                              +------------------+

主线程需要后台线程为其下载图片

方法:

向后台线程发送消息,叫后台线程下载图片。发送消息之前肯定要先创建Message;可以new一个message,再设置该message实例,如上文所述至少需要设置的3个变量:

  • what
  • obj包含下载图片需要的相关信息,比如url;
  • target就需要引用后台线程中的Handler实例。

然后还要调用message引用的Handler的sendToTarget()方法发送该消息(发送消息也是Handler的事情)。最后在后台线程中处理该消息。

在主线程中的操作步骤:

  • 那么先引用该后台线程的Handler,
  • 然后调用Handler.obtainMessage()获取message;使用该方法可以不用手动new一个message,再去设置;这样就比较方便,而且性能更好。
  • 调Message的sendToTarget()方法来发送该消息。

后台线程中下载图片:

  • 后台线程中需要实现了Handler的handleMessage(Message msg)方法
  • 分析what。what表示了消息的种类,如果该消息是要求其下载图片,就执行handleMessage()方法中下载图片的代码片段。

后台线程通知主线程更新视图

后台线程通知主线程图片已经下好,请更新视图的消息。

方法:与之前一样,只是反过来了。这次需要后台线程获取主线程中Handler的引用,并向主线程发送消息。然后主线程接收到消息后会调用 自己的Handler对象的handleMessage()方法,来更新UI。

这里主线程和后台线程都各自有一套:Handler、Looper和Message queue。 后台线程的实现方式为单独创建一个类,并且继承了HandlerThread。这样它就会自动拥有Looper和Message Queue; 但是Handler还是需要自己创建,因为你要为其实现handleMessage()方法;但是你只需要创建Handler即可,创建时Handler中的相关 代码自动会关联该类的Looper。该类还会自动创建子线程并在线程中调用相关方法比如handleMessage()方法;但也不是所有方法都在子线程中 调用,比如你在该类自定义的方法就不会。

后台线程的实现(创建)

  • 单独创建一个类,并且继承HandlerThread
  • 也可以直接在主线程中通过Thead(Runnable run)的方式开启一个普通的子线程,并传入一个Runnable对象。 并以内部类的形式实现Runnable类(这是关键),这样就可以在Runnable类的run()方法中直接访问主线程中的handler对象,并且能够直接访问执行下载动作时需要的数据。 这样就无需主线程发送消息给子线程,并附带下载动作所需的信息了。

Handler相关方法

Handler可通过post方法将一个Runnable投递到Handler内部的Looper中去处理,也可以通过Handler的send方法发送一个message,这个message同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的。

send方法会调用MessageQueue的enqueueMessage方法将message放入队列;Looper处理该message时,最终会调用messag中的Runnable或者Handler的handleMessage()方法。

涉及到Handler的相关方法:

//该方法属于
runOnUiThread(new Runnable() {
        @Override
        public void run() {
            //显示天气信息,在UI线程中
            showWeather();
        }
    });
//View的post()方法,比如常在Activity的onCreate()方法中使用的如下方法
mRefreshLayout.post(new Runnable() { //下拉刷新
    @Override
    public void run() {
        mRefreshLayout.setRefreshing(true);
        //获取网络数据
        fetchLatestZhihuNews();
    }
});

handler.post()等方法: 线程在自己的消息队列中发送一个消息。

//在onRefresh()中使用如下方法进行延时。
//延迟处理程序  a post delayed handler
@Override public void onRefresh() {
    //下拉刷新的延迟
    new Handler().postDelayed(new Runnable() {
        @Override public void run() {
            swipeLayout.setRefreshing(false);
        }
    }, 5000);

当用户离开当前应用,进程就会停止,Handler消息也会随之消亡。

Handler类包含如下方法用于发送、处理消息:

  • void handleMessage(Message msg):处理消息的方法。该方法通常用于被重写。
  • final boolean hasMessages(int what):检查消息队列中是否包含what属性为指定值的消息。
  • final boolean hasMessages(int what,Object object):检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息。
  • sendEmptyMessage(int what):发送空消息。
  • final boolean sendEmptyMessageDelayed(int what,long delayMillis):指定多少毫秒之后发送空消息。
  • final boolean sendMessage(Message msg):立即发送消息。
  • final boolean sendMessageDelayed(Message msg,long delayMillis):指定多少毫秒之后发送消息。

现在看《Android开发艺术探索》第10章:Android的消息机制;就容易理解很多了。

进阶内容

  • TheadLocal的工作原理
  • 消息队列的工作原理
  • Looper的工作原理
  • Handler的工作原理
  • 主线程的消息循环

见:《Android开发艺术探索》第10章:Android的消息机制