天空灰的他妈的像哭过。
从前经常听到大佬们说,Android是一个消息驱动型系统,一直都不懂是什么意思。搞了五年Android,还是个垃圾开发崽,问啥啥不会,再问就CV。每次面试都看一遍Handler,看了这么多次,也是一知半解,总觉得好像会,又好像不会,真的是菜得像狗一样。事实证明,搞IT,还真是要认真动脑子的,不动脑子,就会永远停留在会用的层面上。最终成为我这样,一个CV程序猿,API程序猿,垃圾开发崽。
哎,好好学习下吧。
为什么说Android是一个消息驱动型系统呢?
最近看了很多Android FrameWork的知识,什么AMS,PMS,WMS,SystemServer等等。发现Binder机制用的最多。比如说,我要启动一个新的Activity,就要通过Binder配合AMS发送一个消息,最终配合Handler创建启动这个Activity。同样的,启动Service,发送广播。都是这个大致流程。
用户启动Activity消息-------AMS发送消息给,系统检查要启动的Activity进程是否存在---------检查完毕发送Handler消息创建Activity并启动
也就是说,一个动作驱动下一个动作,下一个动作又驱动下下一个动作,最终返回我们想要的结果。
这大概就是消息驱动型系统吧。
FrameWork说多了我也不会,还是搞Handler吧。
首先看一个Handler初始化的方法
public Handler(@Nullable Callback callback, boolean async) {
.....
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到初始化方法里面搞了一个Looper,通过Looper又搞了一个mQueue。看一下myLooper()方法
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
sThreadLocal是一个线程存储数据的类。通过这个数据类获取到了一个Looper对象,并返回给了Handler。
由于我们的Handler是在主线程创建的,所以sThreadLocal存储的是主线程中的looper对象。
public static void main(String[] args) {
..........
Looper.prepareMainLooper();
..........
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
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");
}
上面这东西就是我们平常所说的主线程,我们的程序都是运行在这个Looper里面,Looper不停的从MessageQueue中拿出消息,处理消息,这也证明了我们Android确实是消息驱动型系统。
可以看到在main()方法中调用了Looper的两个静态方法。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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 static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
从这里看到在这里创建了Looper对象,并且存到了主线程的sThreadLocal中。这样在前面通过sThreadLocal.get()就得到了一个主线程的Looper了
Looper.loop()就是从消息队列中不停的拿出消息,然后分发处理。
最后再来看一下Handler发送消息的过程。
public boolean sendMessageAtTime(@NonNull 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);
}
拿到Handler对应的消息队列,并将新消息加入到消息队列中。
到这里我的分析就完了。
如题,为什么Handler可以实现线程间通讯呢?
从上面的分析可以看到,当我们在子线程中使用handler.sendMessage()的时候,由于这个子线程中的这个handler是在主线程创建的,处理这个消息的Looper,MessageQueue也都是在主线程中创建的。消息一发送,就立马把消息发送到主线程中的这个MessageQueue中去了,然后被Looper调用消息,分发回调给我们的主线程handleMessage()方法。也就是说,这个消息的发送处理,和子线程完全没有关系。
其实,屌大的大佬们已经把Handler的祖宗十八代都分析了好几遍。我这个菜鸡分析只是记录下自己一直迷惑的地方。
想通了这个问题,再回头看看Handler,发现它也不过如此。我甚至能手写一个Handler,嘿嘿,下篇手写一下Android系统。哦,不对,是手写下Handler。