View,Activity,Window三者的关系

本文深入解析了Android中Activity的setContentView方法的工作原理,包括其内部实现机制和与PhoneWindow对象的关系,以及如何设置布局。
    在Activity中,通过setContentView就可以显示xml的布局文件了,也就是把一个个View控件组合在一起,首先,这个Activity的方法setContentView有三个重载的方法。
    
public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
    }
    public void setContentView(View view) {
        getWindow().setContentView(view);
    }
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        getWindow().setContentView(view, params);
    }
    
    可以看出,三个方法什么也没用做,只是调用了getWindw方法。看一下getWindow方法,仅仅是
      
  public Window getWindow() {
        return mWindow;
    }

    mWindwow是在attach方法中创建的,看一看attach方法。有这两行代码
  
  mWindow = PolicyManager.makeNewWindow(this);
    mWindow.setCallback(this);

首先,看看PolicyManager.makeNewWindow(this)是如何处理的。
//通过反射的方式,创建一个Ipolicy的实例对象。
    public final class PolicyManager {  
    private static final String POLICY_IMPL_CLASS_NAME =  
        "com.android.internal.policy.impl.Policy";  
  
    private static final IPolicy sPolicy;  
  
    static {  
       // 运行时动态装载IPolicy实现类   
        try {  
           //加载Policy类的同时会执行其中的静态代码段   
            Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);  
            sPolicy = (IPolicy)policyClass.newInstance();  
        } catch (ClassNotFoundException ex) {  
            throw new RuntimeException(  
                    POLICY_IMPL_CLASS_NAME + " could not be loaded", ex);  
        } catch (InstantiationException ex) {  
            throw new RuntimeException(  
                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);  
        } catch (IllegalAccessException ex) {  
            throw new RuntimeException(  
                    POLICY_IMPL_CLASS_NAME + " could not be instantiated", ex);  
        }  
    }  
  
    // 构造函数私有,保证是单例类   
    private PolicyManager() {}  
  
    // The static methods to spawn new policy-specific objects   
    public static Window makeNewWindow(Context context) {  
        //看看Policy的方法如何产生一个Window的。
        return sPolicy.makeNewWindow(context);  
    }  
  
    public static LayoutInflater makeNewLayoutInflater(Context context) {  
        return sPolicy.makeNewLayoutInflater(context);  
    }  
  
    public static WindowManagerPolicy makeNewWindowManager() {  
        return sPolicy.makeNewWindowManager();  
    }  
} 

查看Policy源码会发现,是new了一个PhoneWindow的实例。那么getWindow返回的就是一个PhoneWindow了。里面肯定也有三个setContentView方法了。

    
public void setContentView(int layoutResID){
        //mContentParent其实就是我们的xml布局显示的ViewGroup,是一个FlameLayout。
        //第一次,为null,就会执行,以后,会首先移除子View。
        if(mContentParent == null){
            installDecor();
        } else{
            mContentParent.removeAllViews();
            //这个方法什么事情也没用做。
            updateInflateParams();
        }
        //加载xml布局到mContentParent中,所以,我们可以猜想installDecor();肯定是可以得到一个mContentParent的。
        mViewInflate.inflate(layoutResID, mContentParent, mInflateParams);
        
        在Activity的attach方法中,还记得我们执行了一句mWindow.setCallback(this);由此看见,这个cb就是这个Activity自己。当Activity发生变化,就会执行onContentChanged方法。
        android.view.Window.Callback cb = getCallback();
        if(cb != null)
            cb.onContentChanged();
    }

查看installDecor方法

      
private void installDecor() {
        if (mDecor == null) {
            /*创建一个DecorView,
                private final class DecorView extends FrameLayout
            */
            mDecor = generateDecor();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        if (mContentParent == null) {
            //根据窗口的风格修饰,选择对应的修饰布局文件,并且将id为content的FrameLayout赋值给mContentParent
            mContentParent = generateLayout(mDecor);
            //......
            //初始化一堆属性值
        }
    }
    
看一下如果mContentParent为null的时候,如何进行的。

protected ViewGroup generateLayout(DecorView decor){
        ......
        根据flag,style等属性获取到layoutResource,其实就是一个xml布局。这个布局分两块,
        LinearLayout
            FlameLayout(title)
            FlameLayout(content)这个其实就是我们的xml布局填充的父View。
        ......


        View in = mViewInflate.inflate(layoutResource, null, mInflateParams);
        decor.addView(in, new android.view.ViewGroup.LayoutParams(-1, -1));
        ViewGroup contentParent = (ViewGroup)findViewById(0x1050000);
        if(contentParent == null)
            throw new RuntimeException("Window couldn't find content container view");
    
        return contentParent;
    }
    
    根据上面的分析,可以知道setContentView都做了哪些事情。
    1:获得PhoneWindow对象。
    2:判断是否存在mContentParent,不存在的话就安装一个decorView,作为整个界面的根布局,里面有一个FlameLayout,其实就是mContentParent,而我们setContentView,把xml或者View作为mContentParent的子View来处理。
    
<think>我们正在讨论Android系统中的几个核心概念:ActivityWindowView、Surface和Layer。它们之间的关系Android图形显示和用户交互的基础。下面我将结合引用内容,逐步解释它们的作用与关联。###1.**Activity**:用户界面的容器-ActivityAndroid应用的基本组件,代表一个用户界面。它负责管理用户交互和生命周期。-每个Activity都持有一个**Window**对象(具体实现是`PhoneWindow`)[^1]。Activity通过`setContentView()`方法将布局设置到Window中。###2.**Window**:视图的承载框架-Window是一个抽象类,负责管理顶级视图(即整个窗口的视图层次结构)。它的实现类是`PhoneWindow`。-Window的主要作用:-创建并管理`DecorView`(整个窗口的根视图)[^1]。-作为ActivityView之间的解耦层,处理窗口属性(如标题栏、背景等)。-Window通过`WindowManager`将视图添加到屏幕上(见下文)。###3.**View**:UI的基本单元-View代表屏幕上的一个矩形区域,负责绘制和事件处理[^2]。-ViewGroup是View的子类,用于容纳多个View,形成树状结构(视图树)。-在Activity中,我们通过`setContentView()`设置的布局文件最终会被添加到`DecorView`的`contentParent`区域中(即ContentView)[^1]。###4.**DecorView**:窗口的根视图-它是`PhoneWindow`的内部类,继承自`FrameLayout`。-包含两个部分:-标题栏(可选,由主题决定)-内容区域(`android.R.id.content`),我们设置的布局就放在这里。-因此,`DecorView`是整个视图树的根节点。###5.**ViewRootImpl**:连接ViewWindowManager的桥梁-`ViewRootImpl`负责:-连接视图树和`WindowManager`[^3]。-处理视图的测量(measure)、布局(layout)、绘制(draw)三大流程。-将绘制结果同步到`Surface`上。-每个`Window`(即每个Activity)对应一个`ViewRootImpl`实例。###6.**Surface**:绘制的画布-`Surface`是一个由屏幕合成器(SurfaceFlinger)管理的原始缓冲区(RawBuffer)的持有者[^5]。-每个`Window`对应一个`Surface`。当视图需要绘制时,`ViewRootImpl`会通过`Surface`获取一个`Canvas`(画布),然后在上面绘制视图内容。-绘制完成后,`Surface`的内容会被提交给SurfaceFlinger进行合成显示。###7.**Layer**:SurfaceFlinger中的显示单元-在Android的底层显示系统(SurfaceFlinger)中,每个`Surface`对应一个**Layer**(具体类型如`BufferLayer`)[^5]。-Layer是SurfaceFlinger管理的最小显示单元,负责存储像素数据(即窗口内容)并参与合成。-SurfaceFlinger将所有Layer按照Z-order(深度顺序)合成为最终帧,输出到屏幕。---###整体协作流程1.**创建窗口**:当Activity启动时,会创建一个`PhoneWindow`,并初始化`DecorView`。2.**设置内容**:调用`setContentView()`将用户布局添加到`DecorView`的内容区域。3.**连接系统服务**:Activity通过`WindowManager`(实际是`WindowManagerGlobal`)将`DecorView`添加到系统中。此时会创建`ViewRootImpl`[^3]。4.**绘制准备**:`ViewRootImpl`负责初始化`Surface`(通过`Session`与SurfaceFlinger通信)。5.**视图绘制**:-`ViewRootImpl`触发视图树的测量、布局、绘制。-绘制过程中,每个View通过`Canvas`在`Surface`上绘制内容。6.**提交显示**:绘制完成后,`ViewRootImpl`将`Surface`的内容提交给SurfaceFlinger。7.**合成显示**:SurfaceFlinger将属于该窗口的`Layer`与其他Layer(如状态栏、其他App窗口)合成,最终输出到屏幕。---###关系总结|组件|作用|关联对象||---------------|----------------------------------------------------------------------|------------------------------||**Activity**|用户交互的容器|持有`PhoneWindow`||**Window**|管理顶级视图结构和窗口属性|持有`DecorView`||**DecorView**|窗口的根视图,包含标题栏和内容区域|是`ViewGroup`的子类||**View**|UI的基本单元,负责绘制和事件处理|组成视图树||**ViewRootImpl**|连接视图树与`WindowManager`,处理三大流程并管理`Surface`|每个`Window`对应一个实例||**Surface**|绘制的画布,持有图形缓冲区|由`ViewRootImpl`创建和管理||**Layer**|SurfaceFlinger中的显示单元,存储窗口像素数据|与`Surface`一一对应[^5]|###示例代码:Activity中视图的添加```javapublicclassMainActivityextendsActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//以下操作在PhoneWindow中完成://1.创建DecorView//2.将R.layout.activity_main添加到DecorView的内容区域setContentView(R.layout.activity_main);}}```###§§相关问题§§1.`ViewRootImpl`在何时被创建?2.Surface的缓冲区是如何分配的?3.多个Activity窗口的Layer在SurfaceFlinger中如何排序?4.硬件加速绘制对Surface和Layer有什么影响?5.DecorView的measure/layout/draw流程是如何触发的?</think>### Android 系统中 Activity、Layer、Surface、WindowView关系解析 #### 1. **Activity:用户交互的容器** - **作用**:Android 应用的基本组件,负责管理用户界面和生命周期。 - **关联**: - 每个 Activity 持有一个 **Window** 对象(具体实现为 `PhoneWindow`)[^1]。 - 通过 `setContentView()` 将 **View** 树附加到 Window 上。 - **关键流程**: ```java // Activity 创建时初始化 Window public class MainActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化 PhoneWindow setContentView(R.layout.main); // 将 View 附加到 Window } } ``` #### 2. **Window:视图的承载框架** - **作用**:抽象层,管理窗口属性和视图层级(如标题栏、背景等),实现类是 `PhoneWindow`[^1]。 - **关联**: - 包含根视图 **DecorView**(继承自 `FrameLayout`)。 - 通过 `WindowManager` 与系统服务通信。 - **关键结构**: ``` Window (PhoneWindow) └── DecorView ├── TitleBar (可选) └── ContentView (用户设置的 View 树) ``` #### 3. **View:UI 的基本单元** - **作用**:屏幕上的矩形区域,负责绘制和事件处理[^2]。 - **关联**: - 通过组合模式形成树状结构(`ViewGroup` 管理子 View)。 - 最终由 **ViewRootImpl** 绘制到 **Surface** 上。 - **绘制流程**: `measure()` → `layout()` → `draw()` → 内容写入 Surface 的缓冲区。 #### 4. **Surface:绘制的画布** - **作用**:共享内存中的图形缓冲区,承载 View 的绘制结果[^5]。 - **关联**: - 每个 Window 对应一个 Surface。 - 由 **ViewRootImpl** 通过 `Surface.lockCanvas()` 获取 `Canvas` 对象供 View 绘制。 - **生命周期**: `SurfaceControl.create()` → `Surface.copyFrom()` → 提交给 **SurfaceFlinger**。 #### 5. **Layer:合成的显示单元** - **作用**:SurfaceFlinger 中的最小合成单元,存储像素数据[^5]。 - **关联**: - 与 **Surface 一一对应**(如 `BufferLayer` 对应 App 窗口)。 - SurfaceFlinger 按 Z-order 合成所有 Layer 输出到屏幕。 - **创建流程**: `WindowManagerService` → `SurfaceControl` → `SurfaceFlinger::createBufferLayer()` --- ### 核心协作流程 1. **初始化** Activity 创建 → 初始化 `PhoneWindow` → 构建 `DecorView` 和 `ContentView`[^1]。 2. **视图管理** `WindowManager` 将 `DecorView` 添加到系统 → 创建 `ViewRootImpl`[^3]。 3. **绘制合成** - `ViewRootImpl` 触发 View 树的绘制流程[^2]。 - 通过 `Surface.lockCanvas()` 获取画布,View 绘制到 Surface 缓冲区[^4]。 - `Surface.unlockCanvasAndPost()` 提交缓冲区。 - SurfaceFlinger 将对应的 **Layer** 合成到屏幕[^5]。 ```mermaid graph LR A[Activity] --> B[Window] B --> C[DecorView] C --> D[View Tree] D --> E[ViewRootImpl] E --> F[Surface] F --> G[SurfaceFlinger Layer] ``` ### 关键关系总结 | 组件 | 依赖关系 | 通信机制 | |-------------|----------------------------------|-----------------------| | Activity | 持有 Window 实例 | 直接调用 | | Window | 持有 DecorViewViewRootImpl | 跨进程通信(Binder) | | View | 依附于 Window 的视图树 | 绘制指令 | | Surface | 被 ViewRootImpl 管理 | 共享内存 + Binder | | Layer | 与 Surface 一一对应 | SurfaceFlinger 内部管理 | ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值