Android源码分析之Handler
接上一篇分析,正如Android doc所说,Handler主要有2方面用处:
1. delay执行同一线程中的某个操作,也就是schedule message、runnable在未来的某一时刻执行;
2. 给另外一个线程发送message、runnable,让某个操作在另一个线程中执行。比如A线程只要能拿到B线程的
handler就能通过此handler在A线程中通过post message、runnable,让这些消息的处理发生在B线程中,从而实现
线程间的通信。AsyncTask就是通过在background线程中通过关联UI线程的handler来向UI线程发送消息的。为了看的
更清楚些,这里摘抄下Looper.java开头处给的一个典型例子:
* This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
在这里,别的线程可以通过LooperThread.mHandler来实现和它的通信。
接下来一点点分析源码,先看几个相关的:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
public interface Callback {
public boolean handleMessage(Message msg);
} /**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
} /**
* 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);
}
}
这个Callback接口里只有一个handleMessage方法返回boolean值,在后面Handler的ctor会用到,一般情况下都是null。这个接口的存在
没什么特殊的含义,只是为了让你不extends Handler就能处理消息而已(正如此方法的doc所说),类似Thread和Runnable接口的关系。
接下来是dispatchMessage方法,我们已经在上一篇分析Message的时候大概提到了。它的处理是如果message自身设置了callback,则
直接调用callback.run()方法,否则Callback接口的作用就显现了;如果我们传递了Callback接口的实现,即mCallback非空,则调用它处理
message,如果处理了(consumed)则直接返回,否则接着调用Handler自己的handleMessage方法,其默认实现是do nothing,如果你
是extends Handler,那么你应该在你的子类中为handleMessage提供自己的实现。
接下来我们首先看看Handler都有哪些关键的字段,源码如下:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
mQueue来自mLooper,mLooper要么是在ctor中显式指定的要么是默认当前线程的,Handler关于Message、Runnable的所有处理都delegate给了mQueue;mCallback是用户提供的Callback实现,默认是null;mAsynchronous表示Handler是否是异步的,默认是同步的。
接下来我们来看各种各样的Handler的ctor(构造器):
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
} /**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Callback callback) {
this(callback, false);
} /**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
*/
public Handler(Looper looper) {
this(looper, null, false);
} /**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
} /**
* Use the {@link Looper} for the current thread
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with represent to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(boolean async) {
this(null, async);
} /**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with represent to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
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) {
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;
} /**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with represent to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我们来看3个参数的版本,即Looper,Callback,boolean,默认looper是关联的当前线程的,callback是null,async是false。当然你愿意也可以分别指定这3个值。关于ctor不需要赘述,看doc、comment就可以很容易理解。
接下来是一堆Handler的obtainMessage函数,其实现都是直接调用Message的静态函数obtain,但相应的message的target字段都自动被设置成了当前的Handler对象。由于Message的源码已在上一篇中分析过了,这里一带而过。
getPostMessage(Runnable r)之类的也很简单,就是将runnable包装成一个Message,其callback字段被设置成了runnable。
接下来的一堆postxxx、sendxxx,最终会调用下面这个方法:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
在这里,message的target被设置成当前的Handler,如果是异步的Handler,则设置message也为异步的,然后入队,uptimeMillis表示绝对时间戳。这里需要提一下的是xxxAtFrontOfQueue方法,这个方法因为每次是将后来的message插在队列的前头,所以可能导致队列中的其他消息没机会得到处理(即饥饿),或得不到及时处理,所以说插队是不好的,慎用。正如其方法doc中所说,其实在我们的工作学习中,我也强烈推荐大家仔细看看相关类、方法的doc。我知道我们这类人都不喜欢写doc,所以既然能有doc那说明真的是必不可少的,挺重要的。
接下来是removeCallbacks相关的,源码:
/**
* Remove any pending posts of Runnable r that are in the message queue.
*/
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
} /**
* Remove any pending posts of Runnable <var>r</var> with Object
* <var>token</var> that are in the message queue. If <var>token</var> is null,
* all callbacks will be removed.
*/
public final void removeCallbacks(Runnable r, Object token)
{
mQueue.removeMessages(this, r, token);
}
其实现也都是delegate给了mQueue,有一点需要注意下就是这些方法会remove掉所有的Runnable r,而不是第一个匹配的
(注意方法名中的s,是复数而不是单数),也就是说一次remove调用可以remove掉之前好多次post的同一个runnable,
如果之前post的runnable还在队列中的话。
removeMessages、hasMessages之类的方法挺简单不过多解释。
Handler类的分析就到这了。。。(由于本人水平有限,欢迎批评指正)
Android源码分析之Handler的更多相关文章
- Android源码分析笔记--Handler机制
#Handler机制# Handler机制实际就是实现一个 异步消息循环处理器 Handler的真正意义: 异步处理 Handler机制的整体表述: 消息处理线程: 在Handler机制中,异步消息处 ...
- Android源码分析-消息队列和Looper
转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/17361775 前言 上周对Android中的事件派发机制进行了分析,这次博主 ...
- Android源码分析-全面理解Context
前言 Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像 ...
- Android源码分析(六)-----蓝牙Bluetooth源码目录分析
一 :Bluetooth 的设置应用 packages\apps\Settings\src\com\android\settings\bluetooth* 蓝牙设置应用及设置参数,蓝牙状态,蓝牙设备等 ...
- Android源码分析(十七)----init.rc文件添加脚本代码
一:init.rc文件修改 开机后运行一次: chmod 777 /system/bin/bt_config.sh service bt_config /system/bin/bt_config.sh ...
- Android源码分析(十六)----adb shell 命令进行OTA升级
一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...
- Android源码分析(十五)----GPS冷启动实现原理分析
一:原理分析 主要sendExtraCommand方法中传递两个参数, 根据如下源码可以知道第一个参数传递delete_aiding_data,第二个参数传递null即可. @Override pub ...
- Android源码分析(十四)----如何使用SharedPreferencce保存数据
一:SharedPreference如何使用 此文章只是提供一种数据保存的方式, 具体使用场景请根据需求情况自行调整. EditText添加saveData点击事件, 保存数据. diff --git ...
- Android源码分析(十三)----SystemUI下拉状态栏如何添加快捷开关
一:如何添加快捷开关 源码路径:frameworks/base/packages/SystemUI/res/values/config.xml 添加headset快捷开关,参考如下修改. Index: ...
随机推荐
- 将 instance 连接到 second_local_net - 每天5分钟玩转 OpenStack(85)
今天是 local network 的最后一个小节,我们将验证两个local network 的连通性. launch 新的 instance “cirros-vm3”,网络选择 second_loc ...
- MySQL Doublewrite Buffer及业务评估
1. 关于Doublewrite Buffe的总结 Doublewrite Buffer:Doublewrite Buffer出现的初衷是防止buffer pool中的脏页刷新到磁盘中,出现部分写的问 ...
- 【Java心得总结三】Java泛型上——初识泛型
一.函数参数与泛型比较 泛型(generics),从字面的意思理解就是泛化的类型,即参数化类型.泛型的作用是什么,这里与函数参数做一个比较: 无参数的函数: public int[] newIntAr ...
- struts2学习笔记--上传单个和批量文件示例
struts2提供了对上传文件的支持,将上传后的文件封装为java.io.File对象,开发者只需要在Action中定义一个File类型的变量,然后直接使用该变量,将它复制到目的目录即可. 单个文件上 ...
- X240 Win10企业版 14279版本 电池标尺白底问题
win10系统更新到14279版本: 电池标尺显示白底,而且右键也不可打开"启动电池管理器-" (1)首先安装lenovo settings 下载地址:http://think.l ...
- Moon.Orm常见问题问答FAQ
有问题在评论,我看到邮件会尽快回复 1.重点了解Db里面的方法.这是核心. 2.关于查询语句MQL:http://www.cnblogs.com/humble/p/3380065.html 3.关于如 ...
- 单片机DA转换实现正弦波
使用的是查表法: 1.c文件: #include "reg52.h" #include <intrins.h> #include <i2c.h> #defi ...
- Chrome立体动画代码
效果预览:http://hovertree.com/code/run/css/x8l6si70.html 请实用Chrome浏览器查看效果,手机上也可以. 代码如下: <!DOCTYPE htm ...
- IIS 配置Http重定向到Https
注意首先要安装url重定向模块 https://www.microsoft.com/zh-CN/download/details.aspx?id=7435 然后在web.config末尾添加如下 ...
- Delphi 取得 iOS 辅助使用里的字型大小
说明:在 iOS 里有一个人性化的辅助设定,可以将字体放大,但这个设定对 Delphi 是不起作用的,还好 Delphi 提供了这个 iOS API 可以取得. 开发环境:Delphi 10 Seat ...