Activity、Dialog、PopupWindow、Toast比较

Activity、Dialog、PopupWindow、Toast比较

先看一下各个窗口类型表格:

类别 Window Type 是否创建PhoneWindow 根View
Activity TYPE_APPLICATION PhoneWindow.getDecorView()
Dialog TYPE_APPLICATION PhoneWindow.getDecorView()
PopupWindow TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW 若mBackground不空,mPopupView = popupViewContainer; 否则mPopupView = mContentView;
Toast TYPE_TOAST com.android.internal.R.layout.transient_notification

以上视图最终都是调用android.view.WindowManagerImpl#addView(View view, ViewGroup.LayoutParams params)来添加到窗口的。

总结一下各个类型窗口添加视图流程:

Activity、Dialog、PopupWindow、Toast比较

关于PopupWindow说明一下:
(参考:https://www.cnblogs.com/shanzei/p/4654817.html)

  • PopupWindow中没有向Activity及Dialog一样new新的Window,所以不会有新的callback设置,PopupView类自身也没有重写Key和Touch事件的处理,也就没法处理事件消费了;
  • 而PopupViewContainer是一个PopWindow的内部私有类,它继承了FrameLayout,在其中重写了Key和Touch事件的分发处理逻辑;
  • 是否设置了PopupWindow的background,决定了根View是否使用PopupViewContainer;
  • 所以如果设置了PopupWindow的background,则点击Back键或者点击PopupWindow以外的区域时PopupWindow就会dismiss;如果不设置PopupWindow的background,则点击Back键或者点击PopupWindow以外的区域PopupWindow不会消失。

关于Toast,这里贴一张stven_king画的Toast流程图:
(来自 https://blog.csdn.net/stven_king/article/details/78775211)
Activity、Dialog、PopupWindow、Toast比较

有个疑问:
为什么系统在创建Acivity或者Dialog的时候封装了PhoneWindow对象,而PopupWindowt、Toast以及我们自己写悬浮窗口的时候并没有使用PhoneWindow对象?
原因参考:https://blog.csdn.net/u013356254/article/details/55116259

  • PhoneWindow的一个作用是给view包裹上一层DecorView。而DecorView中的布局结构,会根据requestWindowFeature()的不同而不同。
  • Activity和Dialog的布局都比较复杂,比如都可能有appbar (toolbar/actionbar)等,因此通过PhoneWindow来封装可以更好的解耦代码。
  • PopupWindow或者Toast的布局比较简单,因此没有必要包裹一层PhoneWindow。