Android 我的复习资料19.Handler
Handler 消息机制
当我们创建一个Handler 的时候,会和一个默认的线程进行绑定,这个默认线程中会有一个
MessageQueue(消息队列).
作用1:定时的去发送一个Message / runnable对象
作用2:我么可以在一个子线程中进行消息发送在HandleMessage更新UI
创建应用时,会默认创建一个UI线程,UI线程默认创建一个Looper,主线程主要是运行一个MessageQueue管理
一些大组件比如Acticity,BroadCastReceiver
一.Handler封装了消息的发送 (主要包括消息发送给谁)
Looper
1.内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向这个消息队列
2.Looper.Looper()方法,就是一个死循环,不断的从MessageQueue取消息,如果有消息就处理消息,没有消息
就阻塞线程
二.MessageQueue,就是一个消息队列,可以添加消息,并处理消息
三.Handler内部会跟Looper进行关联,也就是说Handler的内部可以找到Looper,找到Looper也就是找到了
MessageQueue,在Handler中发送消息就是向MessageQueue中发送消息
总结:handler 负责发送消息,Loopeer负责接收Handler发送的消息,并直接把消息回传给Handler自己.
MessageQueue就是一个存储消息的容器
ActivityThread 默认创建一个Main 默认创建一个Looper 创建Looper时会默认创建一个MessageQueue
在ActivityThread中 ,会首先调用Looper.preparMainLooper()
ThreadLocal 保存线程变量
ThreadLocal set get 有looper抛出异常只能有一个 默认为空 Looper构造方法中会先new
一个MessageQueue
handler Loop.myLooper 返回 一个从ThreadLocal中取出来的Looper 变量
mlooper.mQueue 拿到MessageQueue
sendMessageDelay sendMessageAtTime(Message msg,long dalayMills)
dalayMills(就是得到系统当前时间+设置的延迟时间)
最后把消息放进消息队列中 queue.enqueueMessage(msg,uptimeMills)
添加是会有很多环节 比如 会有判断当前msg.target也就是Handler是否存在 当前消息是否已经被使用
然后是当前线程是够已经退出 死亡
然后才进行添加的操作,并且打上标识已经在使用的标识 msg.markInUse();
最后添加进MessageQueue队列
Looper的轮询 主要是通过Looper.loop方法进行轮询在Loop方法中首先使用myLooper()
也就是从ThreadLocal中拿出来looper的变量 取出消息队列 通过死循环 不停的调用queue.next从中去除消息Message 如果消息为空就return 阻塞
不为空就调用msg.target.dispatchMessage方法 也就是调用Handler自己的方法
在这个如果我们没有写callBack 并且返回一个true 进行一个拦截 name直接回调 handleMessage方法
进行消息的处理
子线程更新UI的几种方式:
Handler.post
Handler.sendMessage
View.Post
runOnUiThread()
当我们view.settext时,会调用checkForRelayout --->invalidate--> p.invalidateChild(this,damage)
--->invalidateChildInparent()-->checkThread() 会判断 nThread与Thread.currentThread
不是的话就抛出异常 常见的那个必须在主线程跟新UI
checkThread() 这个方法是在viewrootimpl 中的 他是在onResume中创建的
viewrootimpl里判断当前View 的线程是否与主线成一致 不是就抛出异常
viewrootimpl在onResume中创建的 所以我们第一次没有休眠时他还没有进行判断
走了这个HandlerResumeActivity方法.
在ActivityThrad中,有一个HandlerResumeActivity方法, getDecorView 最里层的一个布局帧布局
还有ViewManager一个接口进行管理View ,其中有AddView,其中调用了这个AddView 最后可以看到他
初始化了viewrootimpl.