您的位置:首页 > 其它

对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机制有关,待进一步研究。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: