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

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中需要另开线程处理耗时.网络的任务,但是有必须要在UI线程中修改组件.这样做是为了: ①只能在UI线程中修改组件,避免了多线程造成组件显示混乱 ②不使用加锁策略是为了提高性能,因为a ...

  2. Android ListView工作原理全然解析,带你从源代码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44996879 在Android全部经常使用的原生控件其中.使用方法最复杂的应该就是 ...

  3. Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/39057201),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...

  4. 《Android源代码设计模式解析》读书笔记——Android中你应该知道的设计模式

    断断续续的,<Android源代码设计模式解析>也看了一遍.书中提到了非常多的设计模式.可是有部分在开发中见到的几率非常小,所以掌握不了也没有太大影响. 我认为这本书的最大价值有两点,一个 ...

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

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

  6. Android之三种网络请求解析数据(最佳案例)

    AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...

  7. Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

    转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/26810303),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...

  8. 【Android】EventBus 源码解析

    EventBus 源码解析 本文为 Android 开源项目实现原理解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分 ...

  9. android基础---->JSON数据的解析

    上篇博客,我们谈到了XML两种常用的解析技术,详细可以参见我的博客(android基础---->XMl数据的解析).网络传输另外一种数据格式JSON就是我们今天要讲的,它是比XML体积更小的数据 ...

随机推荐

  1. python对比图片

    通过python的PIL模块可以对比两张图片是否相同,具体源码如下 from PIL import Image from PIL import ImageChops def compare_image ...

  2. [洛谷P2183]巧克力

    题目大意:有n块巧克力,每块巧克力有一个大小.巧克力可以切成若干份.现在要你切成大小相等的m块,且尽可能大.求这个大小. 解题思路:我们二分巧克力切成的大小,然后计算能切成多少块,判断即可.由于最大的 ...

  3. 【PRML学习笔记】第四章:分类的线性模型

    一.基础概念 线性分类模型:决策面(decision boundary)是输入向量的线性函数 目标类别的表示"1 of K" :$ t = (0,1,0,0,0)^T$ 二.分类问 ...

  4. csv 模块的基本使用

    csv 模块专门用于读取和写入 csv 文件内容 以下主要讲在 python2 中的使用,在python3中有不同的地方,我会单独指出来 一般的excel表格可以保存为csv格式,然后就可以使用 cs ...

  5. 【转载】python学习之 字符串前'r'的用法

    文章转载:https://www.cnblogs.com/cyiner/archive/2011/09/18/2180729.html 在打开文件的时候open(r'c:\....') 加r和不加'' ...

  6. HDU 4945 2048 DP 组合

    思路: 这个题写了一个背包的解法,超时了.搜了下题解才发现我根本不会做. 思路参见这个: 其实我们可以这样来考虑,求补集,用全集减掉不能组成2048的集合就是答案了. 因为只要达到2048就可以了,所 ...

  7. 获取系统信息(CPU、内存等)

    简述 获取计算机CPU.主板.内存.硬盘.网卡这些信息,Qt中没有相应的处理,所以需要根据平台来做差异化处理.也许Qt为了跨平台,没有提供与操作系统和硬件密切相关的一些功能(如内存.CPU.硬盘等相关 ...

  8. Linux shell 内部变量

    1 TMOUT 来自bash的解释: If set to a value greater than zero, TMOUT is treated as the default timeout for ...

  9. 新手做2D手游该用哪些工具?

    全球手游行业规模将突破250亿美元,越来越多的开发者开始进入手游研发领域,而作为一名菜鸟,很多时候,如果没有其他开发者的建议,会走很多弯路.一开始进入游戏研发领域的时候,你很难知道该选择什么工具.什么 ...

  10. RIP协议的配置

    拓扑图: 要求: 理解RIP协议的工作原理,并通过 RIP 路由协议实现不同网络互通. 配置步骤: 1.配置好 PC 机的 IP 地址等參数. PC 0>ipconfig IP Address. ...