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大牛们的设 ...
随机推荐
- Memcached 数据导出与导入
我们使用 memcached-tool 命令来导出数据: [root@localhost ~]# memcached-tool dump > /tmp/.txt Dumping memcache ...
- 使用 urllib 分析 Robots 协议
(1) Robots Exclusion Protocol,网络爬虫排除标准,也称爬虫协议.机器人协议,用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取(2) Robots 协议以 robots ...
- Unity绘制Png图片
using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; publ ...
- AngularJS的表达式、指令的学习(2)
最近没有那么忙,就来系统学习一下AngularJS吧,昨天简单的认识了一下,今天就从表达式入手吧,嘿嘿. 一.AngularJS 表达式 AngularJS表达式写在双大括号内:{{expressio ...
- g++参数介绍
转自http://www.cnblogs.com/lidan/archive/2011/05/25/2239517.html [介绍] gcc and g++分别是gnu的c & c++编译器 ...
- 设置ADB网络连接目标板
adb connect 网络连接目标板报错,原因参考[http://ytydyd.blog.sohu.com/146260552.html].而且指定 adb connect <IP>:5 ...
- FileReader类和FileWriter类的基本用法示例
package com.example.io; import java.io.File; import java.io.FileReader; import java.io.FileWriter; i ...
- SqlServer 连接远程服务器数据库 实现跨服务器联合查询
第一种: exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 ' exec sp_addlinkedsrvlogin 'IT ...
- LESS CSS 框架简介与使用
简介 CSS(层叠样式表)是一门历史悠久的标记性语言,同 HTML 一道,被广泛应用于万维网(World Wide Web)中.HTML 主要负责文档结构的定义,CSS 负责文档表现形式或样式的定义. ...
- 【Spring源码分析系列】bean的加载
前言 以 BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beans.xml"));为例查看bean的加载过 ...