Android之Handler源代码深入解析
闲着没事。就来看看源代码,看看源代码的各种原理,会用仅仅是简单的,知道为什么才是最牛逼的。
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中需要另开线程处理耗时.网络的任务,但是有必须要在UI线程中修改组件.这样做是为了: ①只能在UI线程中修改组件,避免了多线程造成组件显示混乱 ②不使用加锁策略是为了提高性能,因为a ...
- Android ListView工作原理全然解析,带你从源代码的角度彻底理解
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android全部经常使用的原生控件其中.使用方法最复杂的应该就是 ...
- Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读
转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/39057201),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...
- 《Android源代码设计模式解析》读书笔记——Android中你应该知道的设计模式
断断续续的,<Android源代码设计模式解析>也看了一遍.书中提到了非常多的设计模式.可是有部分在开发中见到的几率非常小,所以掌握不了也没有太大影响. 我认为这本书的最大价值有两点,一个 ...
- Android 开源项目源码解析(第二期)
Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...
- Android之三种网络请求解析数据(最佳案例)
AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...
- Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...
- 【Android】EventBus 源码解析
EventBus 源码解析 本文为 Android 开源项目实现原理解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分 ...
- android基础---->JSON数据的解析
上篇博客,我们谈到了XML两种常用的解析技术,详细可以参见我的博客(android基础---->XMl数据的解析).网络传输另外一种数据格式JSON就是我们今天要讲的,它是比XML体积更小的数据 ...
随机推荐
- 前端学习之路——Git篇
本文只是一个个人学习Git的笔记,如有错误的地方,还望指出,谢谢!参考资料如下: <Git教程--廖雪峰的官方网站 > bootstrap里面的--git_guide Git安装 在网上搜 ...
- requests 后续1
发送带数据post请求 import requests # 发送post请求 data = { } response = requests.post(url, data=data) # 内网 需要 认 ...
- 双系统 windows引导项添加
[root@MiWiFi-R2D-srv ~]# vi /etc/grub.d/40_custom #!/bin/sh exec tail -n +3 $0# This file provides a ...
- jquery validate验证remote时的多状态问题
因为远程验证用户名时可能会出现几种错误情况: 1.用户名字符非法: 2.长度超限: 3.用户名已经存在: 但remote返回的内容只能是布尔型的,即使用dataFilter来过滤也不知道如何对应的把错 ...
- Linux 设备驱动之 UIO 机制(基本概念)
一个设备驱动的主要任务有两个: 1. 存取设备的内存 2. 处理设备产生的中断 对于第一个任务.UIO 核心实现了mmap()能够处理物理内存(physical memory),逻辑内存(logica ...
- HDU 3016 Man Down(线段树)
HDU 3016 Man Down 题目链接 题意:是男人就下100层的游戏的简单版,每次仅仅能从两端下落.求落地最大血量 思路:利用线段树能够处理出每一个线段能来自哪几个线段.然后就是dag最长路了 ...
- cocos2d-iphone 动作
(1)CCMoveTo [CCMoveTo alloc]initWithDuration:<#(ccTime)#> position:<#(CGPoint)#> 參数说明 : ...
- 小米净水器与小区过滤价格水对照.xls
总结:要是一天用水量为7升下面.还是用小区的过滤水为好,合算. 假设过滤水需求量大,可能小米的净水器比較好.当然,小区的要天天去接.要求风雨无阻的. 这点小米的随用随接就更好. 注意一点,小米的还要用 ...
- java学习记录笔记--继承,super,Object类
继承: Java中的继承是单继承的. 1.子类拥有父类的全部属性和方法. 可是属性和方法的修饰符不能使private. 2.能够复用父类的代码. 方法的重写须要满足的条件: a.返回值类型 b.方法名 ...
- C&C控制服务的设计和侦测方法综述——DDoS攻击,上传从宿主机偷窃的到的信息,定时给感染机文件加密勒索等。
这篇文章总结了一些我在安全工作里见到过的千奇百怪的C&C控制服务器的设计方法以及对应的侦测方法,在每个C&C控制服务先介绍黑帽部分即针对不同目的的C&C服务器设计方法,再介绍白 ...