public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}

首先到Handler运行过程的总结:

1、 Looper.prepare()方法

        为当前线程绑定looper。

        在looper构造方法中创建一个messageQueue



    2、 创建handler 重并写handleMessage方法



    3、 使用handler发送消息,终于消息都会发送至messageQueue对象中。在messageQueue其中,全部的message按应该运行的时间的先后顺序,从小到大排列



    4、Looper.loop()

        在此方法中。开启死循环,不断的从messageQueue中取出应该运行的message,并运行message 相应的handler中的dispatchMessage方法。即。运行我们重写的handleMessage方法

參照以上分析在子线程中创建Handler对象:

	new Thread(){
@Override
public void run() {
Message msg = Message.obtain();
Looper.prepare();//若没有调用此方法则抛出异常 Can't create handler inside thread that has not called Looper.prepare()
Handler handler2 = new Handler(){
public void handleMessage(Message msg) {
Toast.makeText(MainActivity.this, "收到子线程message消息", 0).show();
};
};
handler2.sendMessage(msg);
Looper.loop();
}
}.start();

对照在主线程中创建Handler实例对象我们发现,在子线程中创建Handler对象须要在创建前调用Looper.prepare()方法在创建后调用Looper.loop方法,那到底这两个方法是做什么的呢?

先看看系统的Looper.prepare方法:

public static final void prepare() {

        if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 为当前线程绑定一个looper对象,以sThreadLocal为key
sThreadLocal.set(new Looper());
}

即:调用Looper.prepare方法时为当前线程绑定了一个Looper对象,所以Looper.prepare方法仅仅能调用一次。即一个线程仅仅能有一个Looper对象

再看看Looper的构造方法:

 private Looper() {
mQueue = new MessageQueue();
}

由于一个线程仅仅能有一个Looper对象,所以一个线程也仅仅能有一个MessageQueue对象

先让我们看看Handler的构造方法:

public Handler() {
//获得当前线程的looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 获得looper中MessageQueue的引用
mQueue = mLooper.mQueue;
}

再看看系统的Looper.myLooper方法:即获取调用Looper.prepare方法时保存在sThreadLoad的Looper对象,所以Looper.prepare方法要在new Handler方法前调用

    public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}

即:当创建Handler时会先调用Looper.myLooper()方法获取当前线程的Looper对象,假设Looper==null,则抛出异常

通过以上两个方法,当前线程的唯一Looper对象和MessageQueue对象都已创建,接下来该sendMessage了

查看系统源代码可知:sendEmptyMessage等。发送信息的方法,终于都是调用了SendMessageAtTime(msg,when);

而SendMessageAtTime(msg,when);方法终于的目的就是为了queue.enqueueMessage(msg, uptimeMillis);。当中msg为发送的Message对象,uptimeMillis为SystemClock.uptimeMillis() + when

查看系统的enqueueMessage方法,该方法终于实如今messageQueue其中。全部的message按运行的先后顺序,从小到大排列

final boolean enqueueMessage(Message msg, long when) {

            msg.when = when; // 将运行时间设置给msg.when
Message p = mMessages; // 定义变量p = mMessage ,mMessage初终指向对列的第一个Message 对象 if (p == null || when == 0 || when < p.when) {
// 当队列中为空的时候,mMessage = msg
msg.next = p;
mMessages = msg;
this.notify();
} else {
// 否则将要进入队列的msg的运行时间和队列中的message的运行时间进行比較,
// 终于会使messageQueue中的全部的message按时间为顺序从小到大排列
// 即按运行的先后顺序排列
Message prev = null;
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
msg.next = prev.next;
prev.next = msg;
this.notify();
}
}

消息发送成功这时候该调用Looper.loop方法:即完毕了从MessageQueue中取出须要运行的Message。并运行我们重写的handlMessage方法

 public static final void loop() {
//获得当前线程的looper对象及messageQueue对象
Looper me = myLooper();
MessageQueue queue = me.mQueue; //开启while(true)循环
while (true) {
//从消息队列中取出一个message,假设message运行时间不到。那就wait等一会
Message msg = queue.next(); // might block //运行message 相应的handler中的dispatchMessage方法。即。运行我们重写的handleMessage方法
msg.target.dispatchMessage(msg); }
}
}

版权声明:本文博主原创文章,博客,未经同意不得转载。

Handler消息源代码分析的更多相关文章

  1. Memcached源代码分析 - Memcached源代码分析之消息回应(3)

    文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...

  2. handler 源代码分析

    handler Looper 轮询器 MessageQueue 消息对象 1 主线程在一创建的时候就会调用, public static void prepareMainLooper() {}构造方法 ...

  3. RTMPdump(libRTMP) 源代码分析 10: 处理各种消息(Message)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

  4. RTMPdump(libRTMP) 源代码分析 9: 接收消息(Message)(接收视音频数据)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

  5. RTMPdump(libRTMP) 源代码分析 8: 发送消息(Message)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

  6. hostapd源代码分析(二):hostapd的工作机制

    [转]hostapd源代码分析(二):hostapd的工作机制 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004433 在我的上一 ...

  7. Hadoop源代码分析

    http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...

  8. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个 Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home ...

  9. Android应用程序进程启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创 ...

随机推荐

  1. 关于CodeReview(java)(转)

    关于codereview,在平时的开发中,经常忽略的环节,参照目前介绍写好代码的几本书和之前掉进的坑,做了一个总结,分享出来. 为什么要做 通过review规避一些代码层面的问题 提升可读性,方便后续 ...

  2. OpenStack 中的neutron-server启动过程

    neutron-server是neutron的核心组件之中的一个.负责直接接收外部请求,然后调用后端对应plugin进行处理. 其核心启动过程代码主要在neutron.server包中. __init ...

  3. C++设计模式之建造者模式(三)

    4.引入钩子方法的建造者模式 建造者模式除了逐步构建一个复杂产品对象外.还能够通过Director类来更加精细地控制产品的创建过程.比如添加一类称之为钩子方法(HookMethod)的特殊方法来控制是 ...

  4. Flash Android ANE打包之基本流程

    搭建环境这里就不详细说明了 一.Android本地库编写 1.从Flash Air SDK中提取需要的jar包 Android下需要的jar包在Flash Air SDK/lib/android目录下 ...

  5. C#索引器的应用:自已写一个表格

    C#中索引器,在一个类中有很多的同一类型成员的时候,比较适用索引器. 环境:我们假设有一个动物园,里边有很多动物. 用法: 1.先定义一个类,这是成员的类型.在这里就是要定义一个Animal类: pu ...

  6. PS顶级胶片滤镜插件 Alien Skin Exposure v6.x最新通用汉化补丁

    Alien Skin Exposure v6.0 是一款专业的PS胶片调色滤镜软件,使用Alien Skin Exposure可以迅速将照片调出各种胶片效果,如电影胶片.宝丽来胶片效果.波拉潘胶片效果 ...

  7. 辛星分析html中间name和id 差额

    朋友们可以新手也能很容易区分id和class,但不一定很容易区分id和name,以下说一下二者的差别和联系. 首先是联系,它们都能够用来标记一个元素,并且能够用JavaScript来操作,可是操作方法 ...

  8. Javascript Base64编码与解码

    原文:[转]Javascript Base64编码与解码 <html> <head> <META HTTP-EQUIV="MSThemeCompatible&q ...

  9. UVa 103 - Stacking Boxes (LIS,打印路径)

    链接:UVa 103 题意:给n维图形,它们的边长是{d1,d2,d3...dn},  对于两个n维图形,求满足当中一个的全部边长 依照随意顺序都一一相应小于还有一个的边长,这种最长序列的个数,而且打 ...

  10. 使用 angular directive 和 json 数据 D3 随着标签 donut chart演示样本

    使用angular resource载入中priorityData.json中间json数据,结合D3绘制甜甜圈图.执行index.html其结果见于图.: priorityData.json中jso ...