闲着没事,就来看看源码,看看源码的各种原理,会用只是简单的,知道为什么才是最牛逼的。

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源码深入分析的更多相关文章

  1. android 开发Handler源码剖析

    Android的消息机制主要是Handler的运行机制,而讲Handler的机制,又需要和MessageQueue和Looper结合.MessageQueue中文意思是消息队列,虽说叫队列,但是其内部 ...

  2. Android消息机制源码分析

    本篇主要介绍Android中的消息机制,即Looper.Handler是如何协同工作的: Looper:主要用来管理当前线程的消息队列,每个线程只能有一个Looper Handler:用来将消息(Me ...

  3. Android 开源项目源码解析(第二期)

    Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...

  4. 史上最详细的Android消息机制源码解析

    本人只是Android菜鸡一个,写技术文章只是为了总结自己最近学习到的知识,从来不敢为人师,如果里面有不正确的地方请大家尽情指出,谢谢! 606页Android最新面试题含答案,有兴趣可以点击获取. ...

  5. Android framework完整源码下载

    包括cpp等native代码.可zip打包下载. https://github.com/android/platform_frameworks_base/branches/stale Android线 ...

  6. Android动画设计源码地址

    Android动画设计源码地址 http://blog.csdn.net/shanghaibao123/article/details/45223825

  7. 【转】Android 4.3源码的下载和编译环境的安装及编译

    原文网址:http://jingyan.baidu.com/article/c85b7a641200e0003bac95a3.html  告诉windows用户一个不好的消息,windows环境下没法 ...

  8. android仿漫画源码、抽奖转盘、Google相册、动画源码等

    Android精选源码 android实现仿今日头条的开源项目 波浪效果,实现流量的动态显示 美妆领域的app, 集成了摄像头取色, 朋友圈, 滤镜等 android仿漫画源码 android一个视差 ...

  9. android狼人杀源码,桌面源码,猎豹快切源码

    Android精选源码 android实现狼人杀app源码 android实现精心打造的Android基础框架源码 android热门电影的客户端源码 android 实现桌面的Launcher源码 ...

随机推荐

  1. 连接SQL SERVER 2008需要加端口号

    VC2010 ADO 连接SQL SERVER 2008,127.0.0.1,1433,要加上端口,否则连不上.注意:地址和端口之间使用逗号隔开. 连接SQL SERVER 2000可以不加端口号,使 ...

  2. 用Task代替TheadPool

    TheadPool的问题 不支持线程的取消.完成.失败通知等交互性操作 不支持线程执行先后次序 using System; using System.Diagnostics; using System ...

  3. EWM ODO清理功能

    ERP OBD下传到EWM会自动产生拣货任务(通常做法),但如果EWM因库存不足或其它原因无法拣货时一般要差异确认,对ODO行项目进行0确认.但问题是零确认后EWM标准流程是无法回传ERP的. ERP ...

  4. 内存的分配VS回收&构造函数VS析构函数

    之前有一个问题一直困扰着我,就是一个变量出了作用域,我以为这个变量的内存就被回收了,其实不是这样的,昨天问了一个高手,才豁然开朗,自己在看相关代码的反汇编代码,才知道原来真是这样就.这个问题,我想简单 ...

  5. HTTP 错误 500.21 - Internal Server Error 处理程序“ExtensionlessUrlHandler-Integrated-4.0”在其模块列表中有一个错误模块“ManagedPipelineHandler”

    导致这个错误出现的原因是因为.net Framework4.0没有注册 解决方法:打开运行命令行,运行下面的命令: C:\WINDOWS\Microsoft.NET\Framework\v4.0.30 ...

  6. Mac OSX - 如何在bash_profile中配置全局环境变量

    我们知道,在Linux操作系统下,配置环境变量是使用如下命令: vim /etc/profile 在OSX下,我们用如下命令打开环境变量配置文件: open ~/.bash_profile 典型的环境 ...

  7. [Javascript] The "this" keyword

    The very first thing to understand when we're talking about this-keyword is really understand what's ...

  8. nlog(n)解动态规划--最长上升子序列(Longest increasing subsequence)

    最长上升子序列LIS问题属于动态规划的初级问题,用纯动态规划的方法来求解的时间复杂度是O(n^2).但是如果加上二叉搜索的方法,那么时间复杂度可以降到nlog(n).  具体分析参考:http://b ...

  9. Mac下MySQL卸载方法 转载

    mac下mysql的DMG格式安装内有安装文件,却没有卸载文件……很郁闷的事. 网上搜了一下,发现给的方法原来得手动去删. 很多文章记述要删的文件不完整,后来在stackoverflow这里发现了一个 ...

  10. hexdump—Linux系统的二进制文件查看工具

    hexdump 无参: 相当于 hexdump -x 0000000 457f 464c 0102 0001 0000 0000 0000 0000 0000010 0002 003e 0001 00 ...