一、先看一下使用流程
1.在子线程中使用Handler实例
/***********子线程使用Handler实例*********/
private class LooperThread extends Thread
{
public Handler handler;
@Override
public void run()
{
Looper.prepare();
handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
}
};
Looper.loop();
}
}
2、主线程(UI线程)中使用的Handler,Looper等
其实现在android/app/AcitvityThread.java文件中,如下:
public static void main(String[] args) {
//前面一系列配置暂时不用关心
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
/************从这里开始,使用Looper*******************/
Looper.prepareMainLooper();//对比:子线程中使用Looper.prepare();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();//对比:子线程中自创建new Handler()
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();//对比:这里两者相同
throw new RuntimeException("Main thread loop unexpectedly exited");
}
二、查看源码:
(一)prepare()
1、看一下Looper.prepare()的源码:
/** 将当前线程初始化为一个Looper.所以你可以在start loop前先创建Handlers,再引用这个looper;
* 要确保在调用本方法后调用#loop()方法;结束本方法使用#quit();
*/
public static void prepare() {
prepare(true); //对比:下面将会看到主线程中的prepareMainLooper中将会使用prepare(false)
}
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));
}
附I)这里引出了一个sThreadLocal,首先看其定义:
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
ThreadLocal类是个特殊的全局变量,其全局性只体现在自己的所在的线程(类名也体现出该特性),故因此每个线程的Looper都是独立的;
ThreadLocal类Java本身已经给予实现,Android对其进行了实现优化;其主要思想仍为:ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本,Map中元素的键为线程对象,而值对应线程的变量副本。
前面源码中涉及到的get(),set(0方法分别为获取和设置当前线程所对应的线程局部变量值。
2、对比看一下prepareMainLooper():
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
thrownew IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
附II): sMainLooper的定义:
private static Looper sMainLooper;
和前面大致相同,只是定义了一个sMainLooper,get sThreadLocal获得一个Looper,让sMainLooper指向它;
(二)Handler
1、Handler部分源码:
Handler众多构造函数:
public Handler() {
this(null, false);
}
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper) {
this(looper, null, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public Handler(boolean async) {
this(null, async);
}
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/****************重点看此构造函数*********************/
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();//依然通过sThreadLocal获取到当前Thread的Looper实例,可见这里两者联系到一起
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue; //这里MessageQueue是Looper与Handler沟通的桥梁
mCallback = callback;
mAsynchronous = async;
}
附I)mQueue的定义:final MessageQueue mQueue;
可见通过MessageQueue,Handler与Looper联系到一起;
而观察源码可以发现Handler中常用的发送Message的方法如sendMessage等,最终的实现均是Message的enqueue操作,即进入MessageQueue队列。
(三)Looper.loop()处理事件流程
public static void loop() {
final Looper me = myLooper();//依然通过sThreadLocal获取到当前Thread的Looper实例
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;//获取到上面提到过的MessageQueue mQueue
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
/****************循环处理消息*******************/
for (;;) {
Message msg = queue.next(); // 从MessageQueue中取出next消息
if (msg == null) {
// No message indicates that the message queue is quitting.
//表明当前MessageQueue正在退出
return;
}
// 调试信息,跳过
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
/** 开始分派消息*/
msg.target.dispatchMessage(msg);//Message中的定义Handler target,故dispatchMessage
//最终调用Handler中的处理函数;
/** 调试信息,跳过*/
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
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();//回收处理完的消息Message
}
}
当Loop过程检测到有Msg时,会调用Msg的target即其对应的Handler中的dispatchMessage方法对Msg进行处理:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 可以看到这里最终调用重写的函数handleMessage对Message进行处理
handleMessage(msg);
}
}
可以看到具体的处理逻辑,如果Message的callback不为空的话,则调用handleCallback方法,即调用Message的callback(Runnable); private static void handleCallback(Message message) {
message.callback.run();
}
注意这里直接调用callback的run函数,也就是该事件的处理仍然在Handler所在的线程中。
Message设置callback的方法:
// Message.java
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
如果Message没有设置callback,则会接着判断Handler是否设置Callback;如果Handler设置了Callback则会优先处理callback再去处理handleMessage;
先来看Handler设置callback的方法:
// Handler.java
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Callback callback, boolean async) {
......
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去post一个Runnable的方法,就是通过设置callback来实现的:
// Handler.java
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
再看一下Looper的构造函数:
private Looper(boolean quitAllowed) { //构造函数是private的
mQueue = new MessageQueue(quitAllowed);//MessageQueue是Looper创建时就被创建出来的
mThread = Thread.currentThread(); //mThread为当前线程,即Looper与当前线程建立联系
}
由上loop()方法可以简单得出结论,Looper用以处理MessageQueue中的取出的Message,由MessageQueue是Handler及Looper所共用的,取出的Message则交由Handler进行处理。而Handler也能够通过post或者send等方式将Message添加到MessageQueue中供Looper后续进行取出处理。sThreadLocal保证了Looper是线程私有的,所有信息发送与处理都是在本线程中。
prepare()用以在sThreadLocal中创建线程与该线程对应的Looper的键值对;new Handler或者getHandler创建的Handler都根据sThreadLocal.get()进行获取;创建的Handler与Looper共用MessageQueue;loop开始循环处理Messagequeue中的事件。其即为整个流程。
面试题:
1、Handler消息机制
根据ThreadLocal机制,每一个Thread对应一个Looper,创建的Looper类中包含有一个消息队列MessageQueue;Handler与Looper是一对一的对应关系,它可以通过post或者send操作将Message添加到MessageQueue中,因为它的内部有个对象指向MessageQueue。Looper通过perpare方法创建,调用loop开始对事件进行循环处理,它会检测MessageQueue是否有Message,如果存在,则调用Message对应的target的dispatchMessage方法进行处理;如果MessageQueue为空,则进行循环等待。
2、ThreadLocal机制:以线程为作用域,同一变量对于不同线程具有不同的数据副本。
通过set/get函数来实现该线程对应的变量的赋值和获取值。
原理:每一个Thread类中都有一个类型为Values的localValues变量,该变量中有一个Object类型的数据Object[] table,该数组奇数位用来存储ThreadLocal变量对应的key值,偶数位用来保存相对应的value值。通过set赋值,即是取出对应线程中的localValues变量,然后将键值对写入到table数组中;因此这样就保证了多个线程之间互不干扰地存储和修改数据。
3、MessageQueue的工作原理:
MessageQueue实际上是一个单链表,其主要执行消息入队列和出队列的操作;
enqueueMessage方法用来消息入队列,其操作实质上单链表的插入操作;
next方法用来消息出队列,当队列为空时,则会一直阻塞,循环等待;如果不为空,则将该消息从单链表中移除。