服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - 详解Android中Handler的内部实现原理

详解Android中Handler的内部实现原理

2021-04-22 17:12孙群 Android

这篇文章主要介绍了Android中Handler的内部实现原理,对Handler和消息循环的实现原理进行源码分析,需要的朋友可以参考下

本文主要是对handler和消息循环的实现原理进行源码分析,如果不熟悉handler可以参见博文《详解android中handler的使用方法》里面对android为何以引入handler机制以及如何使用handler做了讲解。

概括来说,handler是android中引入的一种让开发者参与处理线程中消息循环的机制。我们在使用handler的时候与message打交道最多,message是hanlder机制向开发人员暴露出来的相关类,可以通过message类完成大部分操作handler的功能。但作为程序员,我不能只知道怎么用handler,还要知道其内部如何实现的。handler的内部实现主要涉及到如下几个类: thread、messagequeue和looper。这几类之间的关系可以用如下的图来简单说明:

详解Android中Handler的内部实现原理

thread是最基础的,looper和messagequeue都构建在thread之上,handler又构建在looper和messagequeue之上,我们通过handler间接地与下面这几个相对底层一点的类打交道。

一图胜千言

我们在本文讨论了thread、messagequeue、looper以及hanlder的之间的关系,我们可以通过如下一张传送带的图来更形象的理解他们之间的关系。

详解Android中Handler的内部实现原理

在现实生活的生产生活中,存在着各种各样的传送带,传送带上面洒满了各种货物,传送带在发动机滚轮的带动下一直在向前滚动,不断有新的货物放置在传送带的一端,货物在传送带的带动下送到另一端进行收集处理。

我们可以把传送带上的货物看做是一个个的message,而承载这些货物的传送带就是装载message的消息队列messagequeue。传送带是靠发送机滚轮带动起来转动的,我们可以把发送机滚轮看做是looper,而发动机的转动是需要电源的,我们可以把电源看做是线程thread,所有的消息循环的一切操作都是基于某个线程的。一切准备就绪,我们只需要按下电源开关发动机就会转动起来,这个开关就是looper的loop方法,当我们按下开关的时候,我们就相当于执行了looper的loop方法,此时looper就会驱动着消息队列循环起来。

那hanlder在传送带模型中相当于什么呢?我们可以将handler看做是放入货物以及取走货物的管道:货物从一端顺着管道划入传送带,货物又从另一端顺着管道划出传送带。我们在传送带的一端放入货物的操作就相当于我们调用了handler的sendmessagexxx、sendemptymessagexxx或postxxx方法,这就把message对象放入到了消息队列messagequeue中了。当货物从传送带的另一端顺着管道划出时,我们就相当于调用了hanlder的dispatchmessage方法,在该方法中我们完成对message的处理。

下面重点介绍handler:

handler是暴露给开发者最顶层的一个类,其构建在thread、looper与messagequeue之上。
handler具有多个构造函数,签名分别如下所示:

  • 1. publichandler()
  • 2. publichandler(callbackcallback)
  • 3. publichandler(looperlooper)
  • 4. publichandler(looperlooper, callbackcallback)

第1个和第2个构造函数都没有传递looper,这两个构造函数都将通过调用looper.mylooper()获取当前线程绑定的looper对象,然后将该looper对象保存到名为mlooper的成员字段中。
第3个和第4个构造函数传递了looper对象,这两个构造函数会将该looper保存到名为mlooper的成员字段中。
第2个和第4个构造函数还传递了callback对象,callback是handler中的内部接口,需要实现其内部的handlemessage方法,callback代码如下:

?
1
2
3
public interface callback {
  public boolean handlemessage(message msg);
}

handler.callback是用来处理message的一种手段,如果没有传递该参数,那么就应该重写handler的handlemessage方法,也就是说为了使得handler能够处理message,我们有两种办法:
1. 向hanlder的构造函数传入一个handler.callback对象,并实现handler.callback的handlemessage方法
2. 无需向hanlder的构造函数传入handler.callback对象,但是需要重写handler本身的handlemessage方法
也就是说无论哪种方式,我们都得通过某种方式实现handlemessage方法,这点与java中对thread的设计有异曲同工之处。
在java中,如果我们想使用多线程,有两种办法:
1. 向thread的构造函数传入一个runnable对象,并实现runnable的run方法
2. 无需向thread的构造函数传入runnable对象,但是要重写thread本身的run方法
所以只要用过多线程thread,应该就对hanlder这种需要实现handlemessage的两种方式了然于心了。

我们知道通过sendmessagexxx系列方法可以向消息队列中添加消息,我们通过源码可以看出这些方法的调用顺序,
sendmessage调用了sendmessagedelayed,sendmessagedelayed又调用了sendmessageattime。
handler中还有一系列的sendemptymessagexxx方法,而这些sendemptymessagexxx方法在其内部又分别调用了其对应的sendmessagexxx方法。

通过以下调用关系图我们可以看的更清楚些:

详解Android中Handler的内部实现原理

由此可见所有的sendmessagexxx方法和sendemptymessagexxx最终都调用了sendmessageattime方法。

我们再来看看postxxx方法,会发现postxxx方法在其内部又调用了对应的sendmessagexxx方法,我们可以查看下sendmessage的源码:

?
1
2
3
4
public final boolean post(runnable r)
{
  return sendmessagedelayed(getpostmessage(r), 0);
}

可以看到内部调用了getpostmessage方法,该方法传入一个runnable对象,得到一个message对象,getpostmessage的源码如下:

?
1
2
3
4
5
private static message getpostmessage(runnable r) {
  message m = message.obtain();
  m.callback = r;
  return m;
 }

通过上面的代码我们可以看到在getpostmessage方法中,我们创建了一个message对象,并将传入的runnable对象赋值给message的callback成员字段,然后返回该message,然后在post方法中该携带有runnable信息的message传入到sendmessagedelayed方法中。由此我们可以看到所有的postxxx方法内部都需要借助sendmessagexxx方法来实现,所以postxxx与sendmessagexxx并不是对立关系,而是postxxx依赖sendmessagexxx,所以postxxx方法可以通过sendmessagexxx方法向消息队列中传入消息,只不过通过postxxx方法向消息队列中传入的消息都携带有runnable对象(message.callback)。

我们可以通过如下关系图看清楚postxxx系列方法与sendmessagexxx方法之间的调用关系:

详解Android中Handler的内部实现原理

通过分别分析sendemptymessagexxx、postxxx方法与sendmessagexxx方法之间的关系,我们可以看到在handler中所有可以直接或间接向消息队列发送message的方法最终都调用了sendmessageattime方法,该方法的源码如下:

?
1
2
3
4
5
6
7
8
9
10
11
public boolean sendmessageattime(message msg, long uptimemillis) {
  messagequeue queue = mqueue;
  if (queue == null) {
   runtimeexception e = new runtimeexception(
     this + " sendmessageattime() called with no mqueue");
   log.w("looper", e.getmessage(), e);
   return false;
  }
  //注意下面这行代码
  return enqueuemessage(queue, msg, uptimemillis);
}

该方法内部调用了enqueuemessage方法,该方法的源码如下:

?
1
2
3
4
5
6
7
8
9
private boolean enqueuemessage(messagequeue queue, message msg, long uptimemillis) {
  //注意下面这行代码
  msg.target = this;
  if (masynchronous) {
   msg.setasynchronous(true);
  }
  //注意下面这行代码
  return queue.enqueuemessage(msg, uptimemillis);
}

在该方法中有两件事需要注意:

  • 1. msg.target = this

该代码将message的target绑定为当前的handler

  • 2. queue.enqueuemessage

变量queue表示的是handler所绑定的消息队列messagequeue,通过调用queue.enqueuemessage(msg, uptimemillis)我们将message放入到消息队列中。

所以我们通过下图可以看到完整的方法调用顺序:

详解Android中Handler的内部实现原理

我们在分析looper.loop()的源码时发现,looper一直在不断的从消息队列中通过messagequeue的next方法获取message,然后通过代码msg.target.dispatchmessage(msg)让该msg所绑定的handler(message.target)执行dispatchmessage方法以实现对message的处理。
handler的dispatchmessage的源码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void dispatchmessage(message msg) {
  //注意下面这行代码
  if (msg.callback != null) {
   handlecallback(msg);
  } else {
    //注意下面这行代码
   if (mcallback != null) {
    if (mcallback.handlemessage(msg)) {
     return;
    }
   }
    //注意下面这行代码
   handlemessage(msg);
  }
}

我们来分析下这段代码:

1.首先会判断msg.callback存不存在,msg.callback是runnable类型,如果msg.callback存在,那么说明该message是通过执行handler的postxxx系列方法将message放入到消息队列中的,这种情况下会执行handlecallback(msg), handlecallback源码如下:

?
1
2
3
private static void handlecallback(message message) {
  message.callback.run();
}

这样我们我们就清楚地看到我们执行了msg.callback的run方法,也就是执行了postxxx所传递的runnable对象的run方法。

2.如果我们不是通过postxxx系列方法将message放入到消息队列中的,那么msg.callback就是null,代码继续往下执行,接着我们会判断handler的成员字段mcallback存不存在。mcallback是hanlder.callback类型的,我们在上面提到过,在handler的构造函数中我们可以传递hanlder.callback类型的对象,该对象需要实现handlemessage方法,如果我们在构造函数中传递了该callback对象,那么我们就会让callback的handlemessage方法来处理message。

3.如果我们在构造函数中没有传入callback类型的对象,那么mcallback就为null,那么我们会调用handler自身的hanldemessage方法,该方法默认是个空方法,我们需要自己是重写实现该方法。

综上,我们可以看到handler提供了三种途径处理message,而且处理有前后优先级之分:首先尝试让postxxx中传递的runnable执行,其次尝试让handler构造函数中传入的callback的handlemessage方法处理,最后才是让handler自身的handlemessage方法处理message。

希望本文对于大家理解android中的handler和消息循环机制有所帮助。

延伸 · 阅读

精彩推荐