对Handler工作原理的分析
2016-04-26 17:42
369 查看
一直对Handler的工作原理非常好奇,看了网上很多帖子还是感觉似懂非懂。今天专门亲自从源码角度分析一下Handler的工作过程。
private Handler
mHandler;
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.tv01);
mHandler =
new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
这是很常规的一种写法,实际上这样写是不对的,这样的话Handler的会持有Activity的引用,导致Activity不能及时得到回收。并且从源码中可以看到
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 followingHandler class should be static or leaks might occur: "
+
klass.getCanonicalName());
}
}
Handler在构造的时候会检查你是否将它声明为单独的一个类,如果没有单独去静态继承Handler类去实现的话发出警告,因为这个问题不是致命的。
正确的方式是这样做,
private static class
MyHandler extends
Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
接下来会发生这个
mLooper = Looper.myLooper();
if (mLooper
== null) {
throw new RuntimeException(
"Can't createhandler inside thread that has not called Looper.prepare()");
}
Looper.myLooper()去拿当前线程的Looper对象。如果是在主线程中Looper.prepare()方法在创建Activity之前已经执行,所以myLooper()会返回一个Looper对象。但是如果是在子线程去调myLooper()是没法拿到Looper对象的。看看Looper::prepare()的源码,
public static void
prepare() {
prepare(true);
}
private static void prepare(boolean
quitAllowed) {
if (sThreadLocal.get() !=
null) {
throw new RuntimeException("Only one Loopermay be created per thread");
}
sThreadLocal.set(new
Looper(quitAllowed));
}
Looper::prepare()方法向ThreadLocal变量中保存了一个Looper对象。
public static @Nullable Looper
myLooper() {
return sThreadLocal.get();
}
而Looper::myLooper()就是将ThreadLocal变量中保存的值返回出去。接下来这句
mQueue =
mLooper.mQueue;
Handler用的Queue是Looper的Queue。
Handler中的发送消息最终都会调到这个方法
public boolean sendMessageAtTime(Message msg, long
uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this +
"sendMessageAtTime() called with no mQueue");
Log.w("Looper",
e.getMessage(),
e);
return false;
}
return enqueueMessage(queue,
msg,
uptimeMillis);
}
而这个方法返回时执行了Handler::enqueueMessage方法
private boolean
enqueueMessage(MessageQueue queue,
Message msg, long
uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg,
uptimeMillis);
}
该方法再返回时又调用了MessageQueue::enqueueMessage方法。此时我们应该去到MessageQueue类中查看源码,
boolean enqueueMessage(Message msg, long
when) {
......
if (p ==
null || when ==
0 || when < p.when) {
// New head, wake up theevent queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else
{
// Inserted within themiddle of the queue. Usually we don'thave to wake
// up the event queue unlessthere is a barrier at the head of the queue
// and the message is theearliest 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;
}
......
}
return true;
}
这个就是将发送来的消息保存到消息队列等待调度。之后的事情就交给Looper来做了。
public static void
loop() {
......
final
MessageQueue queue =me.mQueue;
// Make sure the identityof this thread is that of the local process,
// and keep track of what thatidentity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg ==
null) {
// No message indicatesthat the message queue is quitting.
return;
}
// This must be in a localvariable, 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);
......
}
}
当Looper::loop()方法被调用以后队列就活起来了,不断地获取消息并分发消息。最后就是Handler的回调了
public void dispatchMessage(Message msg) {
if (msg.callback !=
null) {
handleCallback(msg);
} else
{
if (mCallback
!= null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
之后就回到了最开始我们提到的关于如何实例化一个Handler对象,之后覆写里面的Handler::handleMessage(msg)方法。整个消息循环就跑起来了。
这里最大的一个问题在于Looper::loop()中的死循环是如何跑起来的,为什么没有开启新线程执行Looper::loop(),但是也没有阻塞主线程?这个可能与Binder机制有关,待进一步研究。
private Handler
mHandler;
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.tv01);
mHandler =
new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
这是很常规的一种写法,实际上这样写是不对的,这样的话Handler的会持有Activity的引用,导致Activity不能及时得到回收。并且从源码中可以看到
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 followingHandler class should be static or leaks might occur: "
+
klass.getCanonicalName());
}
}
Handler在构造的时候会检查你是否将它声明为单独的一个类,如果没有单独去静态继承Handler类去实现的话发出警告,因为这个问题不是致命的。
正确的方式是这样做,
private static class
MyHandler extends
Handler{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
接下来会发生这个
mLooper = Looper.myLooper();
if (mLooper
== null) {
throw new RuntimeException(
"Can't createhandler inside thread that has not called Looper.prepare()");
}
Looper.myLooper()去拿当前线程的Looper对象。如果是在主线程中Looper.prepare()方法在创建Activity之前已经执行,所以myLooper()会返回一个Looper对象。但是如果是在子线程去调myLooper()是没法拿到Looper对象的。看看Looper::prepare()的源码,
public static void
prepare() {
prepare(true);
}
private static void prepare(boolean
quitAllowed) {
if (sThreadLocal.get() !=
null) {
throw new RuntimeException("Only one Loopermay be created per thread");
}
sThreadLocal.set(new
Looper(quitAllowed));
}
Looper::prepare()方法向ThreadLocal变量中保存了一个Looper对象。
public static @Nullable Looper
myLooper() {
return sThreadLocal.get();
}
而Looper::myLooper()就是将ThreadLocal变量中保存的值返回出去。接下来这句
mQueue =
mLooper.mQueue;
Handler用的Queue是Looper的Queue。
Handler中的发送消息最终都会调到这个方法
public boolean sendMessageAtTime(Message msg, long
uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this +
"sendMessageAtTime() called with no mQueue");
Log.w("Looper",
e.getMessage(),
e);
return false;
}
return enqueueMessage(queue,
msg,
uptimeMillis);
}
而这个方法返回时执行了Handler::enqueueMessage方法
private boolean
enqueueMessage(MessageQueue queue,
Message msg, long
uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg,
uptimeMillis);
}
该方法再返回时又调用了MessageQueue::enqueueMessage方法。此时我们应该去到MessageQueue类中查看源码,
boolean enqueueMessage(Message msg, long
when) {
......
if (p ==
null || when ==
0 || when < p.when) {
// New head, wake up theevent queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else
{
// Inserted within themiddle of the queue. Usually we don'thave to wake
// up the event queue unlessthere is a barrier at the head of the queue
// and the message is theearliest 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;
}
......
}
return true;
}
这个就是将发送来的消息保存到消息队列等待调度。之后的事情就交给Looper来做了。
public static void
loop() {
......
final
MessageQueue queue =me.mQueue;
// Make sure the identityof this thread is that of the local process,
// and keep track of what thatidentity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg ==
null) {
// No message indicatesthat the message queue is quitting.
return;
}
// This must be in a localvariable, 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);
......
}
}
当Looper::loop()方法被调用以后队列就活起来了,不断地获取消息并分发消息。最后就是Handler的回调了
public void dispatchMessage(Message msg) {
if (msg.callback !=
null) {
handleCallback(msg);
} else
{
if (mCallback
!= null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
之后就回到了最开始我们提到的关于如何实例化一个Handler对象,之后覆写里面的Handler::handleMessage(msg)方法。整个消息循环就跑起来了。
这里最大的一个问题在于Looper::loop()中的死循环是如何跑起来的,为什么没有开启新线程执行Looper::loop(),但是也没有阻塞主线程?这个可能与Binder机制有关,待进一步研究。
相关文章推荐
- 【算法逻辑】保持字符串内符号位置不变,其他字符随机变化
- xshell 中 alt+. 快捷键无法使用
- C++第四次作业
- Android_实用技术(3)—— Service简析(Ⅲ)
- mongodb 限制ip访问
- mongodb 限制ip访问
- c文件操作
- git文件内容没变但status显示不同的解决方案
- 开发一定要买台苹果电脑,最好是苹果笔记本
- 数据标准化方法
- 实验室项目日志
- Android小程序-Walker注册页面(四)
- iOS 划线总结
- 序列化之-----transient
- 从 3 个 IT 公司里学到的 57 条经验
- 我的2016书单
- 单例模式
- 增删改查前端部分
- Activity的启动过程--startActivity()
- Apache+PHP开发环境的配置