我们都知道,在子线程中进行UI操作(更新UI控件)包括以下四种方法:
1.Handler的handlerMessage()方法。
2.Handler的post()方法。
3.View的post()方法。
4.Activity的runOnUiThread()方法。
本文重点分析前两种方法,后面两种稍微说一下。在说第一个方法之前,让我们先来看张图片(图片来源于http://my.oschina.net/keeponmoving/blog/61129)
这个图片在很好的说明了Handler中的handleMessage方法的工作原理(至少说明了怎么回事)。但是这个图有个问题,作者把handleMessage画到了主线程的外面,其实应该是要在主线程里面,这样才能通过handleMessage来操作主线程的ui,接下来详细说明原因:
先看看如何创建handler吧,其构造函数如下:
public Handler() {
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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler insidethread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = null;
}
可以看到,mLooper = Looper.myLooper();创建了一个新的Looper对象,mLooper不能为空,如果为空则会抛出异常,我们来看下Looper.myLooper()这个方法:
public static finalLooper myLooper() {
return (Looper)sThreadLocal.get();
}
这个方法功能很简单,就是从sThreadLocal线程中取出Looper对象。如果sThreadLocal线程有Looper对象则返回,如果没有则返回空。那什么时候给sThreadLocal线程设定的Looper对象呢?来看看Looper.prepare()方法吧:
public static finalvoid prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Onlyone Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
其实,我们在使用Handler之前需要调用Looper.prepare()方法,那为什么我们一般在主线程中根本没有调用这个方法啊,其实系统已经帮我们调用了的。ActivityThread中的main()方法源码:
public static void main(String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
EventLogger.setReporter(newEventLoggingReporter());
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler =thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Mainthread loop unexpectedly exited");
}
上面代码的第7行就已经调用了Looper.prepare方法(读者可以继续查看Looper.prepareMainLooper()源代码)。
创建好了handler之后,我们再使用的时候需要调用sendMessage()方法,看代码sendMessage():
Message message = newMessage();
mHandler.sendMessage(message);
从上面的代码可以看出,每次sendMessage的时候都需要先new一个