android(七)Looper Handler分析
一。总结
Looper有一个MessageQueue,用于封装消息循环。 Handler封装了消息投递,消息处理等的辅助类
二。分析
1.从Looper的用法开始分析
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare(); //(1)调用prepare
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop(); //(2)进入消息循环
}
}
(11)prepare做了什么?
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper()); //(12)构造一个Looper,设置到线程本地变量中
}
(12)构造Looper对象
private Looper() {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread(); //得到当前线程
}
所以由(12)可知,prepare把Looper对象保存在线程本地变量中。巧妙地把Looper和调用线程关联起来。
2.Handler-MessageQueue-Looper,三者构成了死循环+消息通信的模型
public static void loop() {
final Looper me = myLooper(); // (21)取得线程本地变量Looper
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue; // 取出Looper中的queue
// 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 (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg); //Handler target; 参照下面的dispatchMessage方法
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.recycle();
}
}
public static Looper myLooper() { //(22)返回线程本地变量Looper
return sThreadLocal.get();
}
所以由(21)、(22)可看出loop()处理本线程消息队列中的消息。
三。Looper, Message,Handler之间的关系
1.Message中有个Handler,指定这个Message由哪个Handler处理
Handler target;
2.分析Handler成员变量
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
3.Handler默认构造函数
public Handler() {
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(); //(31)获得调用线程的Looper
if (mLooper == null) {
throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //(32)获得Looper中的消息队列
mCallback = null;
}
4.Handler的另一个构造函数
public Handler(Looper looper) { //(33)传入某个线程的Looper
mLooper = looper;
mQueue = looper.mQueue; //(34)获得Looper中的消息队列
mCallback = null;
}
由上可知,Handler中的MessageQueue都会指向Looper中的消息队列。
5.There are two main uses for a Handler:
(1) to schedule messages and runnables to be executed as some point in the future;
(2) to enqueue an action to be performed on a different thread than your own.
Handler只有一个消息队列,即MessageQueue。通过post()传进去的Runnable将会被封装成消息对象后传入MessageQueue。当Looper轮询到该线程时,并不会单独开启一个新线程,
而Runnable仍然在当前Looper绑定的线程中执行,Handler只是调用了该线程对象的run()而已。通过post()将Runnable提交到主线程的Looper中可以实现UI的更新。
51.sendMessage
public boolean sendMessageAtTime(Message msg, long uptimeMillis){
boolean sent = false;
MessageQueue queue = mQueue;
if (queue != null) {
msg.target = this; //(41)把处理这个message的Handler设为自己
sent = queue.enqueueMessage(msg, uptimeMillis);
}
else {
RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
}
return sent;
}
2.post
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r; ///*package */ Runnable callback; 将Runnable封装成消息对象
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
6.消息处理
public void handleMessage(Message msg) { //子类要重写的方法
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) { //如果msg本身有callback
handleCallback(msg);
} else {
if (mCallback != null) { //如果handler本身有callback
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg); //最后交给子类处理
}
}
7.msg的Callback
private static void handleCallback(Message message) {
message.callback.run(); //直接调用Runnable的run方法,也就是说不是新建线程来执行
}
android(七)Looper Handler分析的更多相关文章
- Android的消息循环机制 Looper Handler类分析
Android的消息循环机制 Looper Handler类分析 Looper类说明 Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在ru ...
- 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message
作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...
- 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message
原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...
- android的消息处理机制(图+源码分析)——Looper,Handler,Message
android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android ...
- android的消息处理机制(图文+源码分析)—Looper/Handler/Message[转]
from:http://www.jb51.net/article/33514.htm 作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.andro ...
- Android -- 消息处理机制源码分析(Looper,Handler,Message)
android的消息处理有三个核心类:Looper,Handler和Message.其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因 ...
- android的消息处理机制——Looper,Handler,Message
在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...
- (转)Android消息处理机制(Handler、Looper、MessageQueue与Message)
转自 http://www.cnblogs.com/angeldevil/p/3340644.html Android消息处理机制(Handler.Looper.MessageQueue与Messag ...
- android的消息处理有三个核心类:Looper,Handler和Message。
android的消息处理机制(图+源码分析)——Looper,Handler,Message 作为 一名android程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设 ...
随机推荐
- Ubuntu12.04编译Android2.3.4
Ubuntu12.04编译Android2.3.4 1.下载Ubuntuubuntu-12.04-dvd-i386.iso2.使用U盘安装,启动盘制作用unetbootin-windows-568工具 ...
- 你必须知道的10个提高Canvas性能技巧
你还在抱怨自己写的canvas demo徘徊在10帧以下吗?你还在烦恼打开自己写的应用就听见CUP风扇转吗?你正在写一个javascript Canvas库吗?那么下面九点就是你必须知道的! 一.预渲 ...
- SpringMVC系列之URL匹配问题
一.工程目录 二.web.xml配置文件及与其他文件的关系 三.控制器部分 四.返回值 五.url前后缀 六.项目源代码 http://files.cnblogs.com/files/xujian20 ...
- Android之数据存储
概述 1.android中包含5中数据存储方式: SharedPreferences存储数据. ContentProvider存储 文件存储 SQLlite数据库存储 网络存储 Preference ...
- Android开发训练之第五章第四节——Syncing to the Cloud
Syncing to the Cloud GET STARTED DEPENDENCIES AND PREREQUISITES Android 2.2 (API level 8) and higher ...
- c++ map使用问题【运行结果不一样】
map经常把指针作为key,这种情况下. 我们经常会很自然的以为,如果要取元素时,会按照我们存的顺序拿到元素. 但是事实上不是这样的,因为map取得时候是按key的大小排序的,而如果用指针作为key, ...
- Android studio 插件安装
安装插件步骤 一 CodeGlance 最大的用途:可用于快速定位代码.显示在右侧 二 Android Studio Prettify 可以将代码中的字符串写在string.xml文件中 选中字符串鼠 ...
- router之switch
比较路由中有无switch的区别: 代码一: <Router history={history}> <Route exact path="/" component ...
- Ico初步理解
Ico定义:是一个重要的面向对象编程的法则来削减计算机程序的耦合问题(解耦).通俗理解:把运行中程式的控制权从程式本身那里拿过来,放到配置文件中,通过"反射"找到匹配配置文件总的对 ...
- 解决 java.lang.IllegalThreadStateException: Thread already started. 错误
extends:http://blog.csdn.net/liuhanhan512/article/details/7575386 android开发中,对线程的操作比较悲催,start一个线程后,必 ...