什么是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. VS2012下配置OpenCV2.4.5

    最近在折腾了一下VS2012的OpenCVS2.4.5配置,同VS2010下基本相同,做个简单的记录,以备日后查阅. 1. 安装OpenCV 从OpenCV官网:http://opencv.org/下 ...

  2. Android中实现多彩的霓虹灯

    1.布局文件 <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:androi ...

  3. Alamofire源码学习

    Core文件夹:          Alamofire.swift - - - 该文件中主要是给用户提供一些便利的调用方法,用户可以直接调用该文件中的便利方法来使用Alamofire相关功能.     ...

  4. SecureCRT使用sz和rz命令进行文件的上传和下载

    SecureCRT可以使用sz和rz命令进行文件的上传和下载. sz文件下载: 格式:sz 文件名称 即可将服务器的文件下载至本地. rz文件上传: 格式:rz 文件名称 即可将本地文件上传至服务器. ...

  5. LoadRunner参数化取值及连接数据库操作步骤

    很多情况下,参数添加的数据不是十条二十条,也不是一百两百,对于这种大数量的数据我们可以通过数据库将数据导入: 选中要参数化的内容如下图一所示: 方法一,右键---[Replace with a new ...

  6. java日志框架slf4j与log4j

    日志记录自然是非常重要的,但恐怕能记住slf4j与log4j等日志框架配置的人就很少了,这个东西不难,只是配置好后很少会去动它,开发新项目一般也是从其他项目拷贝,或者参照文档 废话不多说,先说log4 ...

  7. Microsoft .NET Native Developer Preview 内部初探(1)

    Microsoft .NET Native Developer Preview 内部初探(1) MS 前段时间发布了.NET Native Developer Preview,被广大人员赋予“C++的 ...

  8. 深入理解Ember-Data特性(上)

    写在前面 最近比较忙,换了新工作还要学习很多全新的技术栈,并给自己找了很多借口来不去坚持写博客.常常具有讽刺意味的是,更多剩下的时间并没有利用而更多的是白白浪费,也许这就是青春吧,挥霍吧,这不是我想要 ...

  9. 可在广域网部署运行的QQ高仿版 -- GG叽叽V2.4,增加远程协助、桌面共享功能(源码)

    QQ的远程协助.或者说桌面共享是一个非常实用的功能,所以,2.4版本的GG复制了它,而且,GG增强了桌面共享的功能,它可以允许指定要共享桌面的区域,这样,对方就只能看到指定区域的桌面,这对节省流量会非 ...

  10. Java多线程14:生产者/消费者模型

    什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...