这几个类经常用到,以前理清后就再未管过,现在突然又迷糊了,现在又理清了,今天做个记录,以后不清楚了看看就清楚了。
有2篇文章写得非常好,我就不贴源码分析了,
Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系
http://blog.csdn.net/lmj623565791/article/details/38377229 点击打开链接
【从源码看Android】03Android MessageQueue消息循环处理机制(epoll实现)
http://blog.csdn.net/ashqal/article/details/32107099 点击打开链接
相信大家看完就非常清楚了,先大概讲下这几个类的原理使用。
Handler:用于线程间消息传递,handleMessage() 可以在主线程执行,也可以在子线程中执行,比如 经常用来子线程完事后通知主线程UI刷新;
Looper:一看名字就能猜到应该是用来做循环用的,调用 loop() 循环取消息队列中的消息,handler再回调 handleMessage() ;
Message:就是装消息的一个实体;
MessageQueue:处理消息实体对象的队列,是阻塞的;
他们怎么工作的呢?
首先创建一个Handler对象,重写handleMessage()方法,当线程完事后就调用handler对象sendMessage()方法,里面会把这个handler对象给message.target引用,然后Looper.loop()方法开启无限循环获取messageQueue中的message,当获取到一个message,message.target (即handler) 去调用dispatchMessage()方法,实际最终调用是handler.handleMessage(),好,到此也就一个循环了。
Looper中的loop()方法一直无限循环吗?
当消息队列没有消息了,那么Looper所在线程就等待了,当有新的消息来继续循环,直到调用quit()方法,才退出循环,不过我们平时多用于主线程和子线程通信,handler在主线程创建的、prepare()、loop()、quit()等方法没直接调用,不代表SDK的其他类不会默默的调用哦。
所以当Handler在子线程中创建的,就需要自己调用prepare()、loop()、quit()等方法了。
主线程中一启动APP就会在ActivityThread中调用一次loop(),所以不需要我们去调用
public final class ActivityThread {
...
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
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());
// 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"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
...
}
public final class Looper {
...
/**
* 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) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
...
}
第23行,Looper.prepareMainLooper();创建一个mianLooper,静态的,全局可用
第39行,Looper.loop(); 当前线程(即主线程)开启无限处理消息循环
关闭APP会调用quit()
public final class ActivityThread {
...
private class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
...
case LAUNCH_ACTIVITY:
if (mInitialApplication != null) {
mInitialApplication.onTerminate();
}
Looper.myLooper().quit();
break;
}
...
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
((SomeArgs) obj).recycle();
}
}
...
}
注意点:prepare()一个线程只能调用一次,否则发生异常,每个线程中最多只有一个Looper、
Looper中只有一个MessageQueue对象;
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
...
public static void prepare() {
prepare(true);
}
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));
}
...
}
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}
不太了解TheadlLocal吗?可以看这篇博客
http://blog.csdn.net/msn465780/article/details/78673656 点击打开链接
sThreadLocal是一个静态成员变量,这里千万不要误解了,我之前误解为所有线程都共享,那么A线程12行set()
Looper实例后,如果B线程执行第9行,那不是不为null,就会抛异常了吗。
第18行,其实sThreadLocal并不是保存Looper实例的,而是Thread中成员变量ThreadLocal.ThreadLoalMap
才是保存Looper实例的
第9行,sThreadLocal.get()是获取当前线程的ThreadLocal.ThreadLoalMap中的Looper实例,这里当前线程为key,
Looper实例为value
HandlerThread, 是官方封装的子线程,继承Thread,可以有Handler + Thread的作用,不过不是用来刷新UI的,因为HandlerThead相关的回调函数都是子线程的,你要刷新UI还得new个Handler去sendMessage(),那它存在的意义呢?
因为Handler + Thread中的Looper对象是在主线程工作的,一般情况消息不多没关系,一旦消息非常多,就是耗时的,可能就会引起UI卡顿,还有一些处理消息的操作并不需要在UI线程中,那么就可以使用HandlerThead,这样就分担了部分主线程的压力。
简单说下HandlerThead的原理把,其实就是一个普通的子线程,然后里面定义了一个Looper,然后用Looper.loop()循环传递消息,因为Looper在哪个线程那么它工作就在哪个线程里面,HandlerThead是子线程,那么它创建的Looper肯定在子线程了,Handler一般情况都创建在主线程用于刷新UI,所以它里面传递消息的Looper也是在主线程的,详细代码分析就不贴了,这个类就100多行代码,相信大家都能看懂,这里还是写下关键代码的分析如下:
public class HandlerThread extends Thread {
...
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
...
}
当创建HandlerThead调用start()方法那么就会开始执行这个run(),同时HandlerThead调用getLooper()传递给Handler,他们几乎是一起开始调用的,不过的会发现里面都有synchronized 关键,这个目的很简单,就是说获取Looper的时候可能Looper还未创建出来,那么就需要同步上锁,getLooper()就停在wait()这,当run()方法创建好Looper了,就用上锁的这个对象调用notifyAll,getLooper就从刚才暂停的地方继续执行,最终返回Looper给Handler。
这里注意:两个方法中synchronized 字段上锁的对象必须同一个,notifyALL、wait方法必须是这个上锁的对象调用,源码中用的this,也是将就原则,反正this都有直接用,当然用其他任何对象都可以。
好了相信基本应该清楚了,又可以愉快玩耍了偷笑