闲着没事,就来看看源码,看看源码的各种原理,会用只是简单的,知道为什么才是最牛逼的。
Handler源码分析那,从使用的步骤来边用边分析:
1.创建一个Handler对象:new Handler(getMainLooper(),this);
这是我常用的一个方式,getMainLooper是获取主线程的Looper,this则是实现CallBack的接口
看一下Handler的构造函数
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);
}
@hide
public Handler(boolean async) {
this(null, async);
}
@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;
}
@hide
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
构造函数的最主要代码作用是参数的初始化赋值:
mLooper = looper;mQueue = looper.mQueue;mCallback = callback; mAsynchronous = async;
这四个参数是主要的参数了。
2.创建一个Message。 Message msg = handler.obtainMessage();
直接调用Handler的源码:
public final Message obtainMessage()
{
return Message.obtain(this);
}
Message中得源码:
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
这里Message是复用的概念,最大能够保持
private static final int MAX_POOL_SIZE = 50;
50个Message的对象。
sPool变量相当于当前的空的没有被使用的Message,通过转换,将当前这个空Message给返回出去。
Message在使用完之后会被回收的,在下面会有提到。
3.给Message赋值,并发送Message : msg.what = 100 ; handler.sendMessage(msg);
what是Message中得一个储值变量。
发送Message则在Handler中得最终指向是以下源码:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
oK,sendMessage给发送给了MessageQueue类,看MessageQueue怎么处理的。
boolean enqueueMessage(Message msg, long when) {
...........
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;
}
if (needWake) {
nativeWake(mPtr);
}
}
.......
}
截取了中间重要的代码说一下。这个是用来干嘛的??
其实就是用来排序的,我们知道的是Message有延迟的消息,延迟消息的时间都是不一样的,when是有大小的,将后执行的Message放到后面。
MessageQueue不是使用一个集合啊或者使用数组去存放的Message,真正排序的是Message的next变量,next变量存放的是当前Message的下一个Message。
发送之后就执行了一个原生的方法nativeWake,这个在这儿就不去探究了。
4.handler消息的处理回调Callback.
public static void loop() {
........
for (;;) {
Message msg = queue.next(); // might block
.....
msg.target.dispatchMessage(msg);
.......
msg.recycleUnchecked();
}
......
}
这个那是Looper种的源码,loop就是循环取MessageQueue中得Message的方法。我去掉了代码,我们可以看到调用了Messa得target变量,这个变量存放的就是Handler,dispatchMessage就是用来分发Message的方法了。看DispatchMessage的源码:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这个就少了很多了啊!
看到了把,回调了callback。这样就完成了整个循环流程。
说一下上面的
msg.recycleUnchecked()方法。同样,看源码:
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
从方法名上可以知道这个是用来回收Message的。
在Message使用完毕之后,不是将MEssage对象销毁,而是存放起来,将其下次重复使用。
Handler运行大概流程就是这样的了。
Looper的类的源码分析,回头再解析。
Android开发交流群:417270671
我的github地址: https://github.com/flyme2012
Android之Handler源码深入分析的更多相关文章
-
android 开发Handler源码剖析
Android的消息机制主要是Handler的运行机制,而讲Handler的机制,又需要和MessageQueue和Looper结合.MessageQueue中文意思是消息队列,虽说叫队列,但是其内部 ...
-
Android消息机制源码分析
本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Me ...
-
Android 开源项目源码解析(第二期)
Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...
-
史上最详细的Android消息机制源码解析
本人只是Android菜鸡一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢! 606页Android最新面试题含答案,有兴趣可以点击获取. ...
-
Android framework完整源码下载
包括cpp等native代码.可zip打包下载. https://github.com/android/platform_frameworks_base/branches/stale Android线 ...
-
Android动画设计源码地址
Android动画设计源码地址 http://blog.csdn.net/shanghaibao123/article/details/45223825
-
【转】Android 4.3源码的下载和编译环境的安装及编译
原文网址:http://jingyan.baidu.com/article/c85b7a641200e0003bac95a3.html 告诉windows用户一个不好的消息,windows环境下没法 ...
-
android仿漫画源码、抽奖转盘、Google相册、动画源码等
Android精选源码 android实现仿今日头条的开源项目 波浪效果,实现流量的动态显示 美妆领域的app, 集成了摄像头取色, 朋友圈, 滤镜等 android仿漫画源码 android一个视差 ...
-
android狼人杀源码,桌面源码,猎豹快切源码
Android精选源码 android实现狼人杀app源码 android实现精心打造的Android基础框架源码 android热门电影的客户端源码 android 实现桌面的Launcher源码 ...
随机推荐
-
android 伸缩控件ExpandableListView 展开失败的可能原因。
(原创)转载请声明出处http://www.cnblogs.com/linguanh/ 问题原型: ExpandableListView 展开失效. --------------------直接看结论 ...
-
Linux/CentOS 服务安装/卸载,开机启动chkconfig命令详解|如何让MySQL、Apache开机启动?
chkconfig chkconfig在命令行操作时会经常用到.它可以方便地设置和查询不同运行级上的系统服务.这个可要好好掌握,用熟练之后,就可以轻轻松松的管理好你的启动服务了. 注:谨记chkcon ...
-
sbt Getting org.scala-sbt sbt 0.13.12 ...
本地仓库被我搞乱了,一气之下整个删掉了本地仓库,再重启sbt卡在Getting这一步. Getting org.scala-sbt sbt 0.13.12 ... 卡住 补充sbt配置文件: 文件结构 ...
-
Quicksum-S.B.S.
quicksum Queation: Given a string of digits, find the minimum number of additions required for the s ...
-
解决微信OAuth2.0网页授权回调域名只能设置一个的问题
https://github.com/HADB/GetWeixinCode GetWeixinCode 解决微信OAuth2.0网页授权回调域名只能设置一个的问题 使用方法 部署get-weixin- ...
-
[OrangePi] Features (the features of Loboris&#39;s Images)
boot0_sdcard.fex, u-boot.fex and kernel (uImage) created from sources kernel built with many feature ...
-
Android数据加密概述及多种加密方式 聊天记录及账户加密 提供高质量的数据保护
Android数据加密概述及多种加密方式 聊天记录及账户加密 提供高质量的数据保护 数据加密又称password学,它是一门历史悠久的技术,指通过加密算法和加密密钥将明文转变为密文.而解密则是通过解密 ...
-
201621123040《Java程序设计》第六周学习总结
1.本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结 2.书面作业 2.1clone方法 2.1.1在te ...
-
Python菜鸟快乐游戏编程_pygame(6)
Python菜鸟快乐游戏编程_pygame(博主录制,2K分辨率,超高清) https://study.163.com/course/courseMain.htm?courseId=100618802 ...
-
POJ1003 – Hangover (基础)
Hangover Description How far can you make a stack of cards overhang a table? If you have one card, ...