1、文件去除重复行
1、大文件分解;每行
2、为什么子线程不能更新UI
3、怎么改造使得子线程可以更新UI
4、子线程的handler
5、Wifi p2p开发
6、蓝牙
7、View.post 和handler.post区别
- 在主线程中使用。在 measure 执行后被调用,故在 onCreate 中使用可获取 View 真实的宽高。
- post 方法中分两种情况:AttachInfo 不为空,直接调用 Handler.post 方法;AttachInfo 为空,将 Runnable 添加到等待队列 HandlerActionQueue 中。(AttachInfo 持有 Handler 对象)
- AttachInfo 的赋值在 View.dispatchAttachedToWindow 中。
- dispatchAttachedToWindow 的调用在 ViewRootImpl.performTraversals。
- ViewRootImp.performTraversals 还会调用 HandlerActionQueue.executeActions 将等待队列中的 Runnable 通过 Handler.post 添加到主线程的执行队列中。
- 等主线程正在执行的 Runnable 任务(TraversalRunnable:绘制三大流程)结束,就会执行我们 post 的 Runnable 任务。
- 故,在绘制流程开始阶段,通过 View.post 的任务被添加到主线程的执行队列中;绘制流程结束后,相关任务被执行。此时便可以获取到 View 正确的宽高。
-
里的处理并非直接执行Runnable,而是统一插入到主线程的MessageQueue中去执行;
-
View.post在不同版本的Android系统中,有着不同的实现,在API24以前,View.post所做的是:当View.post被调用时,直接向ViewRootImpl的mRunQueue中插入一个Runnable,然后在performTraversals()过程中,统一进行处理,这样一来,View.post()就会按照View.post()的调用顺序在”未来的某个时间点“进行执行,这说明:在这一系列的Android版本中,View.post的执行顺序就是本身调用View.post()的顺序 “未来的某个时间点”,这个未来的某个时间点指的是perfromTraversals()中将ViewRootImpl中mRunQueue中的所有Runnable插入到MessageQueue之后的某个时间点。必然在performTraversals()之后。
-
如上图,必须得等到整个perfromTraversals方法体执行完成(包括)后,才有可能执行下一个Message(这里标注为了Runnable),而perfromTraversals()方法体中,会顺序地调用performMeasure()、performLayout()、performDraw()方法,这三个方法走完,意味着视图已经完成了渲染,此时的View.post()执行,必然是能落在视图创建之后
。
而API24及之后的版本中,View.post所做的事情发生了改变,当View.post()调用时,Runnable被插入到View各自的mRunQueue当中,也就是说,每个View都含有一个mRunQueue,当performTraversals()中,也没有统一处理了,而是根据 performTraversals()->dispatchAttachedToWindows()
递归地调用到子View时,子View将自己的mRunQueue插入到主线程的MessageQueue,这意味着:在高版本的执行过程中,View.post()的执行顺序是按照视图被迭代到的顺序。
二、Handler.post调用 MessageQueue.enqueueMessage 方法将当前 Runnable 插入执行队列中。执行队列按 delay 的时间大小从低到高排列,延迟时间短的放在前面,延迟时间长的放在后面。
不同:在 onCreate 中,Handler.post 的任务的执行时间等同于该行代码的执行时间;View.post 的任务的执行时间在 measure 之后,可获取 View 真实的宽高。