消息机制--handler
ThreadLocal: 用来存储不同线程中的数据,在安卓消息机制中,threadloacl用来存储每个线程的looper。
looper:消息循环机制,通过Loop.prepare()方法去创建
新建的looper将持有一下几个变量
private static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
新建looper的过程:
public static void prepare(){
prepare(true);
}
public 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));
}
private Looper(boolean quitAllowed) {
//初始化消息队列
mQueue = new MessageQueue(quitAllowed);
//取得当线线程
mThread = Thread.currentThread();
}
这里着重介绍ThreadLocal中的get()和set()两个方法如下:
存取原则如下:通过线程来映射对应的value,value中维护了一个数组,数组中存放localThread当前对象及对应的数据,存储规则如下:ThreadLocal的值在table数组中的存储位置总是为ThreadLocal的reference字段所标识的对象的下一个位置
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
void put(ThreadLocal<?> key, Object value) {
cleanUp();
// Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) {
// Replace existing entry.
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference;
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
// Remember first tombstone.
if (firstTombstone == -1 && k == TOMBSTONE) {
firstTombstone = index;
}
}
}
Values values(Thread current) {
return current.localValues;
}
handler:
这里先列举下handle的几个构造方法:在新建一个handler对象的时候,其实已经关联了对应线程的looper对象(1.当handle没有动态去设置looper时,根据创建handler的线程,取出looper对象,所以用最终处理消息对应的线程就是创建handler的线程。2.当手动去传对应的looper对象时,最终处理消息的线程是根据looper所在的线程决定的,handle只是looper在执行中的一个对象而已,处理对象是不分线程的),取出了looper的msgqueue
//可以传自定义的looper,callback
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
//平时没有传任何参数时,最终会走到这个方法,参数:null,false
//callback:用来在最后处理消息的时候调用,下文给出
public Handler(Callback callback, boolean async) {
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();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
使用handler去发送消息的过程:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//这里msg被加入消息队列queue
return queue.enqueueMessage(msg, uptimeMillis);
接下来讲解looper如何从msgqueue中取出消息进行处理:
在新建handler对象后,looper要调用loop()方法,不断从msgqueue中取出消息处理,代码如下
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//从Looper中取出消息队列
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
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
//将消息交给target处理,这个target就是Handler类型
msg.target.dispatchMessage(msg);
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();
}
}
从上面loop()方法中,当有msg时,将会执行msg.target.dispatchMessage(msg) 方法,其中msg.target就是handler,这个在sendMseeage时,对msg进行了处理,由此可得最后由handler的dispatchMessage(msg)方法得到执行:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
//这个方法很简单,直接调用msg.callback.run();
handleCallback(msg);
} else {
//如果我们设置了callback会由callback来处理消息
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//否则消息就由这里来处理,这是我们最常用的处理方式
handleMessage(msg);
}
}
其中msg.callback是个Runnable接口的实现,什么时候会设置这个callback:handler.post(runnable),post方法最终会被封装成msg对象传过去
public final boolean post(Runnable run){
return sendMessageDelay(getPostMessage(run),0);
}
mCallback :这个是在新建handler对象的时候传进去的,当没有传时为null
最后才会执行handler的handleMessage(msg)方法
注意事项:
- 在主线程创建handle时,系统默认提供了mainLooper,所以不需要再自己去创建looper了。但是在子线程时,需要自己去创建looper,并要去手动执行loop()方法去轮询查找消息,
- msg在哪个线程执行是依赖handler创建时的线程?还是looper所在的线程?--- 答案是looper所在的线程,因为在处理消息时,最终是由looper的loop()方法调用,再去调用handler对应的handleMessage()方法。
这里注意一点,对象是不分线程的
这里举几个典型的例子:
子线程想要在主线程中执行一段代码
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
//todo
}
})