handler是android中实现线程之间通信的方式之一,他的原理值得我们了解。
handler的通信实现原理离不开MessageQueue,Message和Looper
当handler被创建的时候,会检查其内部引用的mLooper对象是否已经存在。
mLooper= Looper.myLooper();
if(mLooper==null) {
throw newRuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
ThreadLocal是一种以当前thread为key的HashMap,能够将线程间的对象分离开来
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map !=null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if(e !=null)
return(T)e.value;
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map !=null)
map.set(this,value);
else
createMap(t,value);
}
looper以threadlocal的形式存在于thread当中
调用looper.prepare的时候:
private static void prepare(boolean quitAllowed) {
if(sThreadLocal.get() !=null) {
throw newRuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(newLooper(quitAllowed));
}
创建looper的时候会一同创建messageQueue:
private Looper(boolean quitAllowed) {
mQueue=new MessageQueue(quitAllowed);
mThread= Thread.currentThread();
}
在looper的loop方法中不断读取messageQueue的msg
代码:
public static void loop() {
finalLooper me =myLooper();
if(me ==null) {
throw newRuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
finalMessageQueue 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 longident = 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
finalPrinter logging = me.mLogging;
if(logging !=null) {
logging.println(">>>>> Dispatching to "+ msg.target +" "+
msg.callback +": "+ msg.what);
}
final longtraceTag = me.mTraceTag;
if(traceTag !=0&& Trace.isTagEnabled(traceTag)) {
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 longnewIdent = 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();
}
}
网友评论