1、handler在主线程和子线程互相通信(子线程和子线程的通信)简单使用
我们使用handler,可以实现主线程和子线程之间的相互通信,然后子线程和子线程之间的通信,如果不清楚,基本用法请先参考我的这篇博客
Android之用Handler实现主线程和子线程互相通信以及子线程和子线程之间的通信 http://blog.csdn.net/u011068702/article/details/75577005
2、handler在主线程为什么不需要调用Looper.prepare()
我们看下Looper.java这个类,它在安卓android.os包下,我们看这个类的一开始的注释
* <p>This is a typical example of the implementation of a Looper thread, * using the separation of {@link #prepare} and {@link #loop} to create an * initial Handler to communicate with the Looper. * * <pre> * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper.prepare(); * * mHandler = new Handler() { * public void handleMessage(Message msg) { * // process incoming messages here * } * }; * * Looper.loop(); * } * }</pre>
很明显,在一个线程里面需要使用Handler之前需要Looper.prepare(),但是我们平时在主线程更新UI的时候,为什么没有看到这行代码呢?
我们看下ActivityThread.java这个类,它在安卓包名android.app目录下,我们知道ActivityThread.java这个类是安卓程序的入口,我们看下main函数的代码
public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); // Make sure TrustedCertificateStore looks in the right place for CA certificates final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
我们可以看到有Looper.prepareMainLooper()函数,我们点击进去
public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
然后看到了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)); }
我们可以看到这里就调用prepare函数,所以主线程不需要调用Looper.prepare()函数,然后我们也可以看到这里有行这个代码
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
在Looper.java类中,我们的Looper保存在ThreadLocal里面
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
用ThreadLocal修饰的变量,可以理解为只有当前线程可以改变这个参数,其它线程不可以改变这个参数,如果你对ThreadLocal不清楚,单独可以先看下我这篇博客的简单使用
java之ThreadLocal简单使用总结 http://blog.csdn.net/u011068702/article/details/75770226 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); }
上面的代码写得很清楚了,如果当前的sThreadLocal对象里面有个Looper对象,那么就会抛出异常,而且英文也提示了,所以,一个线程为什么只能有一个Looper对象的原因,所以如果在程序里面,每个线程调用2次Looper.prepare()就会报错,我们再看这行代码
sThreadLocal.set(new Looper(quitAllowed));
点击Looper的构造函数
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
里面构建了一个MessageQueue对象,上面我们分析一个线程只有一个Looper对象,那么Looper对象只构建一个,也就意味着MessageQueue对象也只构建一次,所以一个线程也只有一个MessageQueue对象的原因。
在main函数里面,也调用了Looper.loop()函数,后面分析这个方法