C语言handler类作用,Handle的原理(Looper、Handler、Message三者关系)
转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044
介绍
前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理。本文从源码的角度来分析如何实现的。
首先我们得知道Handler,Looper,Message Queue三者之间的关系
- Handler封装了消息的发送,也负责接收消。内部会跟Looper关联。
- Looper 消息封装的载,内部包含了MessageQueue,负责从MessageQueue取出消息,然后交给Handler处理
- MessageQueue 就是一个消息队列,负责存储消息,有消息过来就存储起来,Looper会循环的从MessageQueue读取消息。
源码分析
当我们new一个Handler对象的时候,看看他的构造方法里面做了什么.
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
从源码中我们看到他会调用Looper.myLooper方法获取一个Looper对象,然后从Looper对象获取到MessageQueue对象。
Looper myLooper()
跟进去看看Looper.myLooper()方法做了什么。这是一个静态方法,可以类名.方法名直接调用。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
1
2
3
这个方法里面就一行代码,从sThreadLocal中获取一个Looper对象,sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量。底层是ThreadLocalMap,既然是Map类型那肯定得先set一个Looper对象,然后我们才能从sThreadLocal对象里面get一个Looper对象。
ActivityThread main()
说到这里得给大家介绍一个新的类ActivityThread,ActivityThread类是Android APP进程的初始类,它的main函数是这个APP进程的入口。我们看看这个main函数干了什么事情。
public static final void main(String[] args) {
------
Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
}
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
-----
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在第二行代码调用Looper.prepareMainLooper()方法,第13行调用了Looper.loop()方法。
Looper prepareMainLooper()
继续跟进Looper.prepareMainLooper()方法,在这个方法中第一行代码调用了内部的prepare方法。prepareMainLooper有点像单例模式中的getInstance方法,只不过getInstance会当时返回一个对象,而prepareMainLooper会新建一个Looper对象,存储在sThreadLocal中。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
1
2
3
4
5
6
7
8
9
Looper prepare()
继续跟进prepare方法,看第5行代码,新建了一个Looper对象,调用sThreadLocal.set方法把Looper对象保存起来。看到这里我想聪明的你们肯定明白了为什么new Handler对象的时候调用Looper.myLooper()方法能从sThreadLocal对象中取到Looper对象。
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
1
2
3
4
5
6
Looper 构造方法
文章开头我们就讲到Looper内部包含了MessageQueue,其实就是在new Looper对象的时候就new了一个MessageQueue对象。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
1
2
3
4
Looper loop()
ActivityThread类main方法中调用了Looper的两个方法,前面我们解释了prepareMainLooper(),现在来看第二个方法loop()。
public static void loop() {
final Looper me = myLooper();//获取Looper对象
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//从Looper对象获取MessageQueue对象
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {//死循环 一直从MessageQueue中遍历消息
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
//调用handler的dispatchMessage方法,把消息交给handler处理
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
这个方法的代码呢比较多。我都给代码加上了注释。其实就是一个死循环,一直会从MessageQueue中取消息,如果取到了消息呢,会执行msg.target.dispatchMessage(msg)这行代码,msg.target就是handler,其实就是调用handler的dispatchMessage方法,然后把从MessageQueue中取到的message传入进去。
Handler dispatchMessage()
public void dispatchMessage(Message msg) {
//如果callback不为空,说明发送消息的时候是post一个Runnable对象
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {//这个是用来拦截消息的
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);//最终调用我们重写的handleMessage方法
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
这个方法对消息做最后处理,如果是post类型调用handleCallback方法处理,如果是sendMessage发送的消息。看我们有没有拦截消息,如果没有最终调用handleMessage方法处理。
Handler handleCallback()
看到这里我们知道为什么post一个Runnable对象,run方法执行的代码在主线程了吧,因为底层根本就没有开启线程,就只是调用了run方法而已。
private static void handleCallback(Message message) {
message.callback.run();
}
1
2
3
前面我们从创建handler对象开始,以及创建Looper,创建MessageQueue的整个流程,现在来分析下,当我们调用post以及sendMessage方法时,怎么把Message添加到MessageQueue。
Handler post()
调用了getPostMessage方法,把Runnable传递进去。
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
1
2
3
4
Handler getPostMessage()
首先调用Message.obtain()方法,取出一个Message对象,这个方法之前有讲过,然后把Runnable对象赋值了Message对象的callback属性。看到这里我们也明白了dispatchMessage方法为什么要先判断callback是否为空了吧。
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
1
2
3
4
5
Handler enqueueMessage()
在post方法里面调用了sendMessageDelayed方法,其实最终调用的是enqueueMessage方法,所以我这里就直接看enqueueMessage方法源码。第一行代码就把handler自己赋值给messgae对象的target属性。然后调用MessageQueue的enqueueMessage方法把当前的Messgae添加进去。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
1
2
3
4
5
6
7
总结
总结:handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给Handler自己。MessageQueue就是一个存储消息的容器。
---------------------
作者:安辉就是我
来源:CSDN
原文:https://blog.csdn.net/lowprofile_coding/article/details/72580044
版权声明:本文为博主原创文章,转载请附上博文链接!
C语言handler类作用,Handle的原理(Looper、Handler、Message三者关系)相关推荐
- Handle的原理(Looper、Handler、Message三者关系)
转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044 介绍 前面的内容对Handler做了介绍,也讲解了如何使 ...
- Android异步消息处理机制 深入理解Looper、Handler、Message三者关系
转载子:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自[张鸿洋的博客] 很多人面试肯定都被问到过,请问Android中 ...
- Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
很多人面试肯定都被问到过,请问Android中的Looper , Handler , Message有什么关系?本篇博客目的首先为大家从源码角度介绍3者关系,然后给出一个容易记忆的结论. 1. 概述 ...
- Handle的原理分析
介绍 Handle的原理(Looper.Handler.Message三者关系 前面的内容对Handler做了介绍,也讲解了如何使用handler,但是我们并不知道他的实现原理.本文从源码的角度来分析 ...
- Android 系统(59)---Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)
Android开发:Handler异步通信机制全面解析(包含Looper.Message Queue) 前言 最近刚好在做关于异步通信的需求,那么,今天我们来讲解下Android开发中的Handler ...
- android 消息循环机制--looper handler
Looper类说明 Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在run()方法中的内容执行完之后就退出了,即线程做完自己的工作之后就结 ...
- Android Handler消息队列的实现原理
我们在写Android程序的时候,有经常用到Handler来与子线程通信,亦或者是用其来管理程序运行的状态时序.Handler其是由Android提供的一套完善的操作消息队列的API.它既可以运行在主 ...
- java 泛化_Java语言class类用法及泛化(详解)
这篇文章主要介绍了Java语言class类用法及泛化(详解),大家都知道Java程序在运行过程中,对所有的对象进行类型标识,也就是RTTI.这项信息记录了每个对象所属的类.虚拟机通常使用运行时类型信息 ...
- 用一句话概括Handler,并简述其原理
目录 Q1:用一句话概括Handler,并简述其原理? (1)Handler是什么? (2)Handler的原理是什么? (3)Handler有什么作用? (4)为什么使用handler,Messag ...
最新文章
- 调制优缺点_复合铝基润滑脂和普通润滑脂的区别,复合铝基脂有什么优缺点
- oracle和dba,oracle db、dba和rdba
- 什么叫做“假学习”?什么叫做“真学习”?
- Qt C++属性类型提供给 QML调用(三)
- 【计算机视觉】究竟谁能解决可解释性 AI?
- 通过简单的 ResourceManager 管理 XNA 中的资源,WPXNA(二)
- B - Friends
- ajax:html5上传文件,上传之前可以实现本地预览
- python装饰器详解-python装饰器使用实例详解
- Cloudflare配置网站免费CDN加速使用教程
- 命令查看windows2008是否激活
- R语言实战笔记后续修改
- 八皇后问题(回溯问题)
- 多个路由器设置静态路由 不同网段可以互相访问
- 邮件发送html, 分别用p,code,xmp三个标签嵌入代码段后的样式比较
- 计算机电脑网络电缆,笔记本电脑的网络电缆在哪里
- macbookair苹果MAC笔记电脑本更换电池教程
- 《Modulated Fusion using Transformer for Linguistic-Acoustic EmotionRecognition》论文翻译
- 多种经典色差计算公式——matlab代码
- Maya快捷键学习游戏的方法有很多,但是自学和老师带是不一样
热门文章
- 小米max刷原生android,小米max标准版 魔趣OS 安卓10 MagiskV21版 完美ROOT 纯净完美 原生极简 纯净推荐...
- 解决selenium模拟浏览器爬取(淘宝、微博等需要登陆验证的网站)多次登陆问题
- 鬼笔环肽蛋白研究——罗丹明标记鬼笔环肽
- MATLAB中果蝇味道浓度判定函数,果蝇优化算法MATLAB实现
- Detail-revealing Deep Video Super-resolution 中文翻译
- 计算机操作教学计划,计算机操作基础教学计划.doc
- 腾讯阿里原来是这样设计api的
- 深度学习之---起源
- 我们如何成为ebay卖家?ebay入驻条件
- 程序员35岁被裁只能开滴滴、送外卖?这条晋升道路你一定别错过