Dialog dismiss 流程

来源:互联网 发布:java object to date 编辑:程序博客网 时间:2024/06/05 12:03
  1. Dialog.dismiss():
    • 如果是在非UI线程调用,会将dismiss这个指令schedule到UI线程的handler来异步执行
    • 否则同步执行。
  2. Dialog.dismissDialog()。
  3. WindowManagerImpl.removeViewImmediate(mDecor), mDecor在Dialog show()的时候调用mWindow.getDecorView()获得。
  4. WindowManagerGlobal.removeView(view, true): WindowManagerGlobal是进程级的单例,本进程内所有Window相关信息进行集中管理的结点,也包括了ViewRootImpl(Window的View树根节点)
    • 根据传入的view通过findViewLocked()在mViews**(维护了所有当前Window的DecorView)**中找到其所属Window对应的index.
  5. WindowManagerGlobal.removeViewLocked(int index, boolean immediate):
    • 根据index获得Window的ViewRootImpl.
    • 回调本进程的InputMethodManager的windowDismissed(mViews.get(index).getWindowToken())来告知输入法窗口某个Window即将dismiss,从而使得输入法窗口消失(finishInputLocked(), 如果当前输入法的servedView属于该Window的话)。
    • 调用ViewRootImpl的die(immediate), 如果返回true, 代表die()没有被立刻执行,而是schedule(defer)到将来。
      • 如果defer, 那么将此View加入到mDyingViews来保持追踪。
  6. ViewRootImpl.die(boolean immediate):
    • 如果需要立刻执行(immediate == true)或者当前没有在进行Traversal(ViewRootImpl的一个操作,可以简单理解为对整个View树的measure+layout+draw)中,那么可以立即开始(doDie()), 进而返回false代表操作没有被defer.
    • 否则schedule一个MSG_DIE来defer die()。
  7. ViewRootImpl.doDie():
    • 如果已经dead(mRemoved == true), 不需要再死一次。
    • 标记为dead(mRemoved = true)
    • 如果该View之前被添加到了WMS中(mAdded = true), 调用dispatchDetachedFromWindow()来分发detach。
      • dispatchDetachedFromWindow():
        • 会回调其AttachInfo的ViewTreeObserver的dispatchOnWindowAttachedChange(false)
        • 会回调ViewRootImpl承载的View(mView)的dispatchDetachedFromWindow将detach的消息分发到整个View tree。
        • mView(DecorView)的parent设为null(assignParent(null))
        • mView = null, 释放DecorView。
        • 释放Surface(mSurface = null)。
        • 调用mWindowSession.remove(mWindow)来将ViewRootImpl对应的Window从WMS中移除
        • 释放InputChannel,不再接收input信息。
        • unscheduleTraversals()取消之前schedule的Traversal任务(窗口都消失了,不再需要)。
    • 如果添加到了WMS,但是还从来没有进行过Traversal(mFirst == false)
      • invalidateDisplayLists()
      • destroyHardwareRenderer()
      • 下面的逻辑会判断mView != null, 不过在4.4的源码中,很奇怪,因为如果mAdded, 那么dispatchDetachedFromWindow()必然会将mView设置为null, 而这个判断进行的前提也是mAdded,即在进入这个判断中时,mView就一定是null了,mView != null的逻辑似乎永远不会进入到,因此这段逻辑不分析。
    • 重置mAdded = false。
    • WindowManagerGlobal.getInstance().doRemoveView(this), 告知WindowManagerGlobal该ViewRootImpl已经完成了自己的remove相关操作(WMS那边也已经知晓并开始remove了),后者会彻底消除ViewRootImpl在其内部的相关信息:包括在mRoots, mParams,mDyingViews中的信息.
    • 至此,Window在本地Window体系中的信息基本都被清除了。
  8. Session: Session是每个ViewRootImpl和WMS通信的RPC节点
    • remove(IWindow window)最终会RPC调到WMS的removeWindow(this, window)
  9. WMS.removeWindow(Session session, IWindow client):
    • 通过windowForClientLocked(session, client, false)获取到Window对应的WindowState(win, 等于是该Window在WMS体系中的代理人和信息保存者).
    • 为了多线程安全,会synchronized mWindowMap这个保存所有WindowState的map再向下执行。
    • removeWindowLocked(session, win).
  10. WMS.removeWindowLocked(Session session, WindowState win)
    • win.disposeInputChannel(), 注销对应的mInputChannel,不再接收input消息。
    • 如果window之前是可见的,并且已经为其分配了Surface:
      • 会安排一个合适的结束动画(WindowManagerPolicy.TRANSIT_EXIT/TRANSIT_PREVIEW_DONE)
      • 使用window的WindowStateAnimator来驱动此动画(applyAnimationLocked().
      • 如果确实发起了结束动画, 那么会将winState的mExiting设置为true.
        • 并且设置win.mRemoveOnExit = true, win.mDisplayContent.layoutNeeded = true
        • performLayoutAndPlaceSurfacesLocked()来开始动画。
        • 结束函数,真正的remove会在动画结束以后进行。
    • removeWindowInnerLocked(session, win):
    • 如果之前window是可见的并且其消失会导致Configuration的变化(比如横屏变竖屏),那么会schedule一个H.SEND_NEW_CONFIGURATION来处理新的Configuration.
    • updateFocusedWindowLocked, 让新的window获取焦点。
  11. WMS.removeWindowInnerLocked(Session session, WindowState win):

    • 遍历Window的ChildWindow,递归的对每个childWindow进行removeWindowInnerLocked.
    • 如果当前输入法的target是此Window,那么显然需要为输入法找到下一个合适的target(moveInputMethodWindowsIfNeededLocked(false))
    • 将window从PhoneWindowManager中移除(mPolicy.removeWindowLw(win))
    • 调用WindowState的removeLocked()来让其完成自己内部的资源释放清理。
    • 将相关信息从mWindowMap移除。
    • windows/mPendingRemove/mResizingWindows中都移除此Window的相关信息。
    • 释放window的相关token, (WindowToken, AppWindowToken)
    • 如果当前WMS并不在layout过程中(mInLayout = false):
      • assignLayersLocked(windows)根据最新的windows信息(删除了此window的)来重新为window分配layer。
      • win.mDisplayContent.layoutNeeded = true, 表明此window所属的DispalyContent需要进行layout.
      • performLayoutAndPlaceSurfacesLocked() 发起一次layout.
  12. 简单的总结下:

    • Dialog的dismiss本质是其Window从WMS中被remove。
    • Dialog的Window remove 流程和Activity的一致
    • 某种意义上讲,Window体系有两套,本地(WindowManagerGloabl + WindowManagerImpl)和远端(Session + WMS)
    • 本地Window体系负责维护本进程(一般是一个App)所有Window相关信息
    • WMS则是整个系统的Window管理者和真正的操作执行者
    • Window的remove要先在本地(WindowManagerGlobal以及WindowManagerImlp这一套本地的Window机制)执行/登记,然后再到远端(WMS,本地的remove触发了Session向远端发起请求)执行
0 0
原创粉丝点击