主线程消息循环简介
主线程就是ActivityThread,在ActivityThread的main方法中,新建了Looper并开启了Looper循环。循环开启后,每当有新消息进入,Looper会处理对应的消息,处理完后进入休眠状态,主线程的一系列操作都是在这种循环中完成的,这就是主线程的消息循环。
Handler运行机制
-
什么是Handler
Handler在日常开发中,我们经常会接触到,通常会用来在非UI线程中调用,用来通知主线程进行一些UI操作。这其实只是Handler的一个使用场景。
其实Handler是Android消息机制的上层接口,使用Handler可以方便的将一个任务切换到Handler所在的线程中去执行,所以Handler并不是专用来更新UI的,更新UI只是Handler的一个使用场景。
-
Handler、MessageQueue和Looper是如何配合运行的
Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程,这三者实际上是一个整体,只不过我们在开发过程中,比较多的接触到Handler而已。
这里说一下Handler的工作原理:
- Handler创建时候,会采用当前线程的Looper来构建内部的消息循环系统,如果当前线程没有Looper则会抛出异常。所以Handler需要在有Looper的线程中运行。
- 如果当前线程没有Looper,我们需要创建。创建Looper的方法包括
prepare()
和prepareMainLooper()
,其中第二个方法是主线程专用的创建Looper方法 - Looper创建完成后,就可以开始消息循环了。每当有新的消息时候,会调用Handler的post方法,实际上post最后调用Handler的send方法,该方法会向MessageQueue中加入一条数据。
- Looper会不断的轮询MessageQueue中的next()方法,当上一步中有数据加入后,next方法会返回新加入的数据,Looper获取到数据后,回调Handler的disPathMessage方法。
- 因为Handler会在Looper所在的线程中运行,所以至此实现了切换一个任务到Handler所在线程执行的操作。
主线程循环为什么不会卡死
-
首先说一下为什么Android要采用消息循环的机制来设计UI线程。
因为在系统运行中,最小单位是线程,当一个线程运行结束后,系统会销毁对应线程。而UI线程需要一直运行,为了保持线程的活力,所以采用死循环的方式来启动UI线程
-
死循环是否过于消耗CPU资源?
主线程的死循环是基于消息队列机制,当MessageQueue没有消息时候,主线程都处于休眠状态,直到下一个消息到达。在休眠装态时候,并不消耗CPU资源。所以只要不在主线程上进行大量的耗时操作,是不用担心主线程一直占用CPU而使应用卡死的。
普通点击事件中的消息逻辑
-
事件分发之前的操作
-
在点击事件分发之前,其实屏幕的物理点击操作是通过Handler消息机制来传递给主线程的
-
每个Activity都实现了一个特殊的接口
Window.Callback
-
在Activity的attach方法中,会通过setCallback方法,使window持有Activity对象
-
在Activity启动以后,在它的onResume以后,DecorView才开始attahc给WindowManager,从而显示出来。在这个过程中会创建ViewRootImpl,在ViewRootImpl的setView中,会通过跨进程的方式向WMS发起一个调用,从而将DecorView最终添加到Window上,在这个过程中,ViewRootImpl、DecorView和WMS会彼此关联,同时会创建InputChannel、InputQueue和WindowInputEventReceiver来接收点击事件的消息。
-
点击时候,首先会调用
ViewRootImpl.dispatchInputEvent()
方法,此方法实现效果如下:public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) { SomeArgs args = SomeArgs.obtain(); args.arg1 = event; args.arg2 = receiver; Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args); msg.setAsynchronous(true); mHandler.sendMessage(msg); }
-
此处可以看出,通过mHandler发出一个消息,这个消息会通过一系列循环的调用,调到DecorView的dispatchTouchEvent方法,这个方法会获取callback对象,而Activity实现了Callback接口,至此消息传递到Activity
-
具体的Event传递过程可以参考大神任玉刚的博客
-