您的位置:首页 > 其它

Handler机制的源码分析

2017-10-18 19:14 281 查看

Handler,MessageQueue,Looper的关系

Looper的作用是在线程中处理消息的

MessageQueue用来存储消息的队列

Handler使用来定义具体处理消息的方式,以及发送消息;Android主线程中持有一个可以更新UI的Handler;对其他的线程,如果需要处理消息,可以自己new一个Handler在线程的 run 方法中。

ThreadLocal:MessageQueue对象,和Looper对象在每个线程中都只会有一个对象,怎么能保证它只有一个对象,就通过ThreadLocal来保存。Thread Local是一个线程内部的数据存储类,通过它可以在指定线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储到数据,对于其他线程来说则无法获取到数据。

一.Looper

源码分析:
Looper.prepare()方法;创建一个Looper的实例,但是该实例在一个线程中只能有一个;保存在ThreadLocal中,如果发现已经存在了Looper对象,会抛出一个异常。

public static void prepare() {
prepare(true);
}
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));
}


Looper.loop()方法;loop()方法中有一个无限的循环。for(;;)那一段;线程执行到loop()方法之后会一直留在loop()方法中,直到被打断终止 (源码可以看出,发送空消息就可以打断该循环,终止该线程)

public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 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
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.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
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();
}
}

二.Handler

重要的构造方法:

传入某个线程thread的Looper对象;这样这个Handler就是该thread的Handler了(和在该thread的run方法中直接new一个没有参数的Handler的效果是一样的;但是在外部定义可以使我们更好使用)

/**
*  Use the provided {@link Looper} instead of the default one.
*
*  @param looper The looper, must not be null.
*/
public Handler(Looper looper) {
this(looper, null, false);
}

/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}

三.MessageQueue

MessagerQueue是一个单向链表

HandlerThread

HandlerThread是Android系统自己实现的一个可以实现 处理异步消息 的线程。简单来说就是和UI线程是一样的原理,通过Looper和Message通信,让该线程为我们服务。

具体可以看源码就能知道他的原理(我们自己也可以写这样的线程,但是系统给我们的总是要好一点的)

@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}

HandlerThread的使用

HandlerThread workThread = new HandlerThread();
workThread.start();
Handler handler = new Handler(workThread.getLooper());
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: