Android Activity、Window、View 三者关系

01.Window,View,子Window

  • 弹窗有哪些类型
    • 使用子窗口:在 Android 进程内,我们可以直接使用类型为子窗口类型的窗口。在 Android 代码中的直接应用是 PopupWindow 或者是 Dialog 。这当然可以,不过这种窗口依赖于它的宿主窗口,它可用的条件是你的宿主窗口可用
    • 采用View系统:使用 View 系统去模拟一个窗口行为,且能更加快速的实现动画效果,比如SnackBar 就是采用这套方案
    • 使用系统窗口:比如吐司Toast

02.什么是Activity

  • Activity并不负责视图控制,它只是控制生命周期和处理事件。真正控制视图的是Window。一个Activity包含了一个Window,Window才是真正代表一个窗口。
  • Activity就像一个控制器,统筹视图的添加与显示,以及通过其他回调方法,来与Window、以及View进行交互。

03.什么是Window

  • Window是视图的承载器,内部持有一个 DecorView,而这个DecorView才是 view 的根布局。
  • Window是一个抽象类,实际在Activity中持有的是其子类PhoneWindow。PhoneWindow中有个内部类DecorView,通过创建DecorView来加载Activity中设置的布局R.layout.activity_main
  • Window 通过WindowManager将DecorView加载其中,并将DecorView交给ViewRoot,进行视图绘制以及其他交互。

04.什么是DecorView

  • DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图。

    • DecorView作为顶级View,一般情况下它内部包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。
    • 具体情况和Android版本及主体有关,以其中一个布局为例,如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <!-- Popout bar for action modes -->
    <ViewStub
    android:id="@+id/action_mode_bar_stub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inflatedId="@+id/action_mode_bar"
    android:layout="@layout/action_mode_bar"
    android:theme="?attr/actionBarTheme" />

    <FrameLayout
    style="?android:attr/windowTitleBackgroundStyle"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/windowTitleSize">

    <TextView
    android:id="@android:id/title"
    style="?android:attr/windowTitleStyle"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@null"
    android:fadingEdge="horizontal"
    android:gravity="center_vertical" />
    </FrameLayout>

    <FrameLayout
    android:id="@android:id/content"
    android:layout_width="match_parent"
    android:layout_height="0dip"
    android:layout_weight="1"
    android:foreground="?android:attr/windowContentOverlay"
    android:foregroundGravity="fill_horizontal|top" />
    </LinearLayout>
  • 在Activity中通过setContentView所设置的布局文件其实就是被加到内容栏之中的,成为其唯一子View,就是上面的id为content的FrameLayout中,在代码中可以通过content来得到对应加载的布局。

    1
    2
    ViewGroup content = (ViewGroup)findViewById(android.R.id.content);
    ViewGroup rootView = (ViewGroup) content.getChildAt(0);

06.关系结构图

  • Activity 与 PhoneWindow 与 DecorView 关系图
    • image

07.Window创建过程

  • App点击桌面图片启动过程
    • image
  • window启动流程
    • image
  • Activity 与 PhoneWindow 与 DecorView 之间什么关系?
    • 一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。