什么是Handler?

Android 的官方解释:

文档分节1:A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. 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.

这个解释给我们释放出以下几个信息:

一 Handler可以发送和处理两种类型的事物:

1,Message;

2,实现Runnable接口的对象

二,每个Handler实例都会跟创建Handler的Thread及这个Thread下的MessageQueue相关联。

文档分节2: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主要有两个作用:

1,可以设定某个时间点去执行Message和Runnable对象

2,可以在不同的线程中去执行某项任务

文档分节3:Scheduling messages is accomplished with the post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable, long),sendEmptyMessage(int), sendMessage(Message), sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).

Handler主要提供了两种方式来调度消息:

1,post方式:处理Runnable对象

2,sendmessage方式:在Message中放入Bundle data,这个消息会在Handler提供的handleMessage(Message)方法中去处理;

文档分节4:When posting or sending to a Handler, you can either allow the item to be processed as soon as the message queue is ready to do so, or specify a delay before it gets processed or absolute time for it to be processed. The latter two allow you to implement timeouts, ticks, and other timing-basedbehavior.

When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. Thegiven Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.

1,我们可以让handler马上或者指定一个时间间隔发送消息;

2,当我们的应用开启时,UI线程会自动帮我们创建好MessageQueue,我们也可以在自己定义的Thread中创建。

这些信息我们现在只要稍微有个概念就好,一会进入Handler的深入分析之后,自然就会清楚,我们先来分析一下Handler的源码:

先来看看Handler主要的成员变量:

 final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;

我们先粗略地看一下,Handler这个类里面有MessageQueue,从名称中我们可以猜测,这个就应该是消息队列了,第二个成员变量:Looper,从名称来看,应该是个推动消息循环的角色,第三个成员变量:Callback,应该是个回调的接口,剩下的两个先暂时忽略,这三个比较重要的成员变量咱们先混个眼熟,打个招呼就好,现在我们来看一下这个类的构造方法,依次先从最简洁的构造方法看起:

    public Handler() {
this(null, false);
}
 public Handler(Callback callback) {
this(callback, false);
}
    public Handler(Looper looper) {
this(looper, null, false);
}
    public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
    public Handler(boolean async) {
this(null, async);
}
    public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
         //想必大家对下面这句话不陌生吧?细心的朋友们会经常在开发环境中看到这句黄色警告(该Handler可能会导致内存泄漏),后面的系列我们再给出解决这个警告的示例代码
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
} mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
//这个抛出的异常信息大家也可能一不小心就会看到
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
     public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

我了个大去,稍微看去洋洋洒洒出现了7个构造方法,仔细看下,其实前面五种构造方法都调用到了最后两种构造方法中的一种,那么我们就着重来看一下这两个构造方法

public Handler(Callback callback, boolean async)的构造方法里面都干了些啥?
1,通过Looper的myLooper()方法,得到一个Looper对象,将之传给Handler的成员变量mLooper;
如果拿到的这个对象为null,就会抛出异常,从异常的信息来看,说是没有在创建Handler的时候去调用Looper的prepare()方法;
2,从得到的Looper对象拿出MessageQueue对象,传给Handler的成员变量mQueue;
3,将入参callback传给Handler的成员变量mCallback;
看到这里,朋友们可能会发现这个Looper看来是个重要角色啊,忍不住想去一窥究竟,先忍一忍,好戏总是在后头,先来看一下另外一个重要的构造方法
public Handler(Looper looper, Callback callback, boolean async)
其实这个方法做的就是上面那个构造方法的事情,只不过,mLooper,mQueue,mCallback都是在调用之前就已经创建好了,直接赋值而已 上面已经看了Handler这个类的成员变量,构造方法,那么,我们现在就来看一下这个类里面都给外部提供了哪些接口和方法
    public interface Callback {
public boolean handleMessage(Message msg);
}

原来Callback真的就是一个接口,提供了一个回调的方法 handleMessage(Message msg),这个方法的名字有点熟悉,是不是就是我们经常见到的那个在新创建一个Handler的时候,需要覆盖的方法呢?先带着疑问往下看,

 /**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}

看到这个类的注解,大家马上发现上面的疑问是自己多想了,两个方法虽然同名,但是返回类型不同啊,原来这个方法才是我们常见的那个需要覆盖的方法。

接着往下看,

在文章开头的文档分节3中,我们知道,Handler主要提供了两种方式来发送消息,一种是postXX方法,一种是sendMessageXX方法

果然,我们看到了大量的post和sendmessage方法

    public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
   public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
 public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
 public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
    public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
 public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}

细心的朋友们仔细一看,就能发现,其实不管是postXX还是sendMessageXX方法,最终调用的都是sendMessageAtTime这个方法,postXX方法只是不是多调了getPostMessage()方法而已 ,那么我们就来看一下这个方法做了些什么事情:

  private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
} private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}

首先获取一个Message,然后把Runnable对象传递给Message的callback变量,返回一个Message;

我们在文章开头中的Handler的官方文档中提到这么一句话

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.
那么,这里的callback就是这个Runnable object了!
然后我们接着看sendMessageAtTime到底做了些啥?关键的代码就在最后一句:
return enqueueMessage(queue, msg, uptimeMillis);
从这个方法名中,我们可以知道它是让这个消息入列,我们来看一下它的具体实现:
 boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
} synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
msg.recycle();
return false;
} msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
} // We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

分析第2行:msg.target,这个target指的是啥呢?我们这里先暂时不管,后来具体分析Message这个类的时候,我们会分析到

分析第10行:mQuitting,如果这个变量为true,那么就会抛出一个异常,在后续的分析IntentService的时候,我们会遇到这个异常,在这里先有个印象;

分析第33-45行:这里就是把消息按照消息的时间顺序进行排列而已,即把消息队列中的消息按照时间进行排序,并没有执行真正的入列操作,那什么时候执行真正的入列操作呢?后面分析Looper这个类的时候,我们会分析到


  /**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}

从方法名称来看,这个方法是用来分发消息的,我们进入方法里面看一下,首先先判断Message的callback是否为空,这个callback到底是个啥?跟进去看一下

    /*package*/ Runnable callback;

是个Runnable,这里就是我们在getPostMessage这个方法中提到的把Runnable对象传递给Message的callback变量,也就是说,如果我们调用Hander的postXX的方法,那么就会把这个Runnable对象赋值给Message的callback变量,那么在上述代码的第五行中,当这个变量不为空的时候,就会调用handleCallback(msg):这个方法去处理消息,

private static void handleCallback(Message message) {
message.callback.run();
}

看到这里,大家就明白了,我们调用Handler 的postXX方法时,可以在这个Runnalble对象的run方法里去执行UI操作了。

接着分析上面代码的else分支,

 else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}

如果Handler的mCallback成员变量如果不为空,那么就调用这个接口的handleMessage方法,否则的话,就走handleMessage(msg)方法,

    /**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}

好了,这下终于到我们比较熟悉的Handler的处理消息方法上去了,这个方法就是我们在Handler里处理UI操作的方法了。

本篇只是单独地对Handler这个类分析它的内部实现及对外提供的接口及方法,并没有对与Handler紧密相关联的Looer类,MessageQueue类,Message进行分析,目的是为了清晰地对单个封闭的类进行感性的认识之后,再对与之关联的类相互之间的关联调用进行分析;

总结:

1,Handler可以处理 Message及Runnable对象;

2,Handler提供多种构造方法,从而得到与之紧密关联的Looper对象,MessageQueue对象等;

3,Handler提供了两种类型的发送消息的方法,post版本及sendMessage版本

4,Handler提供了重要的dispatchMessage方法,在这个方法中明确是把消息给Runnable对象的run方法还是给Handler子类的handlMessage方法执行UI操作。

 

 

Android Handler的使用示例:结合源码理解Android Handler机制(一)的更多相关文章

  1. 源码分析Android Handler是如何实现线程间通信的

    源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...

  2. Android 进阶14:源码解读 Android 消息机制( Message MessageQueue Handler Looper)

    不要心急,一点一点的进步才是最靠谱的. 读完本文你将了解: 前言 Message 如何获取一个消息 Messageobtain 消息的回收利用 MessageQueue MessageQueue 的属 ...

  3. 50个Android开发人员必备UI效果源码[转载]

    50个Android开发人员必备UI效果源码[转载] http://blog.csdn.net/qq1059458376/article/details/8145497 Android 仿微信之主页面 ...

  4. [转载] 50个Android开发人员必备UI效果源码

    好东西,多学习! Android 仿微信之主页面实现篇Android 仿微信之界面导航篇Android 高仿QQ 好友分组列表Android 高仿QQ 界面滑动效果Android 高仿QQ 登陆界面A ...

  5. Android进阶:五、RxJava2源码解析 2

    上一篇文章Android进阶:四.RxJava2 源码解析 1里我们讲到Rxjava2 从创建一个事件到事件被观察的过程原理,这篇文章我们讲Rxjava2中链式调用的原理.本文不讲用法,仍然需要读者熟 ...

  6. Android 网络图片查看器与网页源码查看器

    在AndroidManifest.xml里面先添加访问网络的权限: <uses-permission android:name="android.permission.INTERNET ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  8. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  9. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

随机推荐

  1. Swift的基本类型和流程控制

    Swift  是一门静态的强类型语言.它以简单.干净.可读性好等特点著称. 1. 为什么是静态语言? 首先静态语言比之动态语言,更具有安全性.它不允许类型之间自动的进行转换,必须要显示的转换.Swif ...

  2. 【Java】深深跪了,OJ题目Java与C运行效率对比(附带清华北大OJ内存计算的对比)

    看了园友的评论之后,我也好奇清橙OJ是怎么计算内存占用的.重新测试的情况附在原文后边. -------------------------------------- 这是切割线 ----------- ...

  3. 使用属性android:onClick,出现异常NoSuchMethodException

    在Activity中注册点击事件有两种方式,setOnClickListener或在xml中设置控件的android:onClick="gotoSecond"属性,在Activit ...

  4. hdu 5104 素数打表水题

    http://acm.hdu.edu.cn/showproblem.php?pid=5104 找元组数量,满足p1<=p2<=p3且p1+p2+p3=n且都是素数 不用素数打表都能过,数据 ...

  5. angularjs 表单验证(不完整版)

    针对项目实践表单验证总结: angular 的 form表单验证:form内需要novalidate取消默认验证,用ng自己的验证,form的名字是非常必要的 栗子:以注册为栗子,下面是注册的部分: ...

  6. UIViewController的生命周期(根视图view从无到有的过程)

    UIViewController的生命周期实质上是指根视图view从无到有的过程 1.首先新建一个工程:不从mainstoryBoard加载 (删除入口) 在AppDelegate.m --> ...

  7. iOS 项目改名~~~~~

    今早出现一个改名的囧事...先记录下...在此之前感谢整理过这片文章的作者 --- GarveyCalvin ,插眼!以下是正文---- 前言:在iOS开发中,有时候想改一下项目的名字,都会遇到很多麻 ...

  8. 从为什么String=String谈到StringBuilder和StringBuffer

    前言 有这么一段代码: public class TestMain { public static void main(String[] args) { String str0 = "123 ...

  9. 原创教程:《metasploit新手指南》介绍及下载

    原创教程:<metasploit新手指南>介绍及下载 1.1 作者简介 这份教程并不是“玄魂工作室”原创,但是我还是要力推给大家.相比那些一连几年都在问“我怎么才能入门”的人而言,我们更欣 ...

  10. 创业6&7

    周末两天泡咖啡店. 起不来,只好下午去. 周六5点到9点. 周日3点到12点. 1)整理直播课程讲义.完成50%. 2)修改GMTC演讲稿.完成. 招行的单子还是拒了,目前还没准备好高可用的App服务 ...