美文网首页
Toast will not show before try/c

Toast will not show before try/c

作者: _夜雨 | 来源:发表于2018-01-04 01:11 被阅读32次

工作中有一个需求,先弹出ProgressDialog的进度条,再做一下耗时操作,为了模拟耗时,于是直接使用了Thread.sleep(),代码很简单:

ProgressDialog

但是奇怪的是,实际效果并没有是先显示ProgressDialog,后Sleep,而是直接先Sleep,再弹出进度条,这个就太奇怪了。

按理来说,中间不掺杂任何异步操作,也不涉及到子线程等等,但是效果却不是按照同步进行。

于是进行了一番尝试,分别使用了Toast,PopupWindow来尝试了一下:

Toast Popupwindow

然后发现结果依然是先sleep,再展示view 。

外部代码看起来很简单,所以只能去内部看一下源码,以ProgressDialog为例:

首先来说,Dialog的对象创建不可能是异步的,首先比较怀疑是对应的show()方法有问题,

那我们首先来看一下Show(),其实里面废话比较多,直接看主要代码:

show()部分代码

其实可以看到,通过调用windowManager.addView来更新界面布局。

那么接下来进行测试:

测试addView

结果显而易见,就是会先sleep,再addView()。

那么就说明addView()本身是一个异步操作,我们进去看一眼ViewGroup的addView()方法:

ViewGroup.addView()

至于为什么addView()是异步,暂时搁置。

然后看一下WindowManager的addView(),实际上就是WindowManagerImpl,进去看一下:

WindowManagerImpl.addView() WindowManagerGlobal.addView()

接下来就只能看ViewRootImpl的setView()方法了:

ViewRootImpl.setView()

其中可以看到,也是调用了requestLayout():

requestLayout()

再进入到ViewRootImpl的scheduleTraversals(),这个方法本身是一个异步方法

scheduleTraversals()

首先看一下mTraversalRunnable,它 是一个 Runnable 对象:

mTraversalRunnable类 doTraversal()

这里面最终会调用performTraverslas()方法,这个方法其实就是View工作流程的核心方法,会分别调用measure,layout,draw方法,从而刷新界面。

不过我们还是要看一下scheduleTraversals的异步问题,其实主要是在于mChoreographer对象,通过postCallback()将Runnable,

scheduleTraversals

接下来我们进去看一下,通过源码可以看到postCallback其实调用了postCallbackDelayedInternal():

postCallbackDelayedInternal

核心代码在于这里面:

异步 scheduleFrameLocked()

可以看到无论是哪一种情况,都会针对message进行msg.setAsynchronous(true);的处理,

那么表示该message没有target,主线程的Handler添加SyncBarrier,这样其实就相当于让其他

的Message全部被delay掉,只保证view能够最先被加载,没有使用

sendMessageAtFrontOfQueue(),是因为我们也可以改动方法,所以保证View最先被执行的

方式就是将Message给setAsynchronous(true)。

setAsynchronous说明 示例图

参考:

Android View 深度分析requestLayout、invalidate与postInvalidate

Android事件机制详细解读

相关文章

网友评论

      本文标题:Toast will not show before try/c

      本文链接:https://www.haomeiwen.com/subject/grzknxtx.html