深入理解Activity的显示原理(1)

Activity的启动

启动Activity其实就是给Activity创建实例,分配任务栈,执行生命周期回调。Activity是如何被显示在屏幕上的,作为应用层的开发者我们其实只做了一件事情,就是在onCreate生命周期调用Activity的setContentView。剩下的是framework层以下的代码和硬件共同来完成的了。

scss 复制代码
setContentView(R.layout.activity_main);

熟悉Activity生命周期的肯定都知道,执行到onResume生命周期的时候,Activity才是可见的。所以要弄清楚Activity的显示原理。需要弄懂两个问题

第一,setContentView方法都做了哪些事情?

第二,到onResume()这个生命周期里,Activity做了哪些事情?

Activity.setContentView做了什么

1、初始化mWindow

在Activity.java中,setContentView方法会先调用getWindow获取一个window类型的实例,然后再继续调用window的setContentView方法。获取到的window实例其实是Activity中的一个叫做mWindow的属性。在attach方法中可以看到mWindow其实是一个PhoneWindow类型的实例。

scss 复制代码
    private Window mWindow;
    
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, ......) {
        ......

        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);

    	......
    }

2、调用mWindow.setContentView

接着看PhoneWindow的setContentView方法,mContentParent如果为空做了两件事installDecor和inflate,如果不为空,那么将移除所以子View进行复用。

ini 复制代码
	ViewGroup mContentParent;

    private DecorView mDecor;

    public void setContentView(int layoutResID) {

        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

    	......
			//将contentView加载到DecorVoew当中
            mLayoutInflater.inflate(layoutResID, mContentParent);
    	......
	}


	
    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            //实例化DecorView
            mDecor = generateDecor(-1);
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
            ......
        }
    }

	//得到mContentParent
    protected ViewGroup generateLayout (DecorView decor){

        ......
        int layoutResource;
        if (features ...) {// 根据feature选择系统布局
            layoutResource = ...
        }
    	
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
        //找到contentParent
		ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
        
        return contentParent;
    }

在mContentParent为空的时候,会调用installDecor方法。

installDecor中当mDecor为空的时候,调用generateDecor来创建一个mDecor。DecorView其实是Framelayout的一个子类。

再往下当mContentParent为空的时候,就会调用generateLayout的方法,赋值mContentParent。在generateLayout方法中,首先会根据features选择一种系统布局样式。接着调用onResourcesLoaded方法,根据系统布局的ID把它转化成View,依然是通过inflated的方式。再通过addView把它添加为DecorView的子View。

java 复制代码
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
	final View root = inflater.inflate(layoutResource, null);
	addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}

generateLayout里面的在最后会把contentParent返回。因为contentParent添加了我们自己实现的布局,也就是contentView。所以可以理解为contentParent其实是系统布局中留给contentView的位置。那么DecorView就是系统布局的父view,这个DecorView是整个Activity的ViewTree显示的RootView。Activity的setContentView中的UI是DecorView中的一部分ContentView。

Activity、PhoneWindow、DecorView、ContentView的关系

一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。DecorView 中的一个子视图ContentView,用于显示我们写的xml布局。

  1. Activity:代表应用程序中单个屏幕上的用户界面。
  2. PhoneWindow:是 Activity 的一个子类,用于管理 Activity 的窗口和界面。每个 Activity 都有一个与之关联的 PhoneWindow 对象,用于控制窗口的外观、布局和交互行为。
  3. DecorView:是 PhoneWindow 中的一个重要组件,它是窗口的根布局视图。DecorView 包含了整个窗口的内容,包括状态栏、标题栏、导航栏和应用程序自定义的界面元素。
  4. ContentView:是 DecorView 中的一个子视图,用于承载应用程序的主要内容界面。

总结

总结一下setContentView的作用。

第一个就是创建DecorView,这是个FrameLayout;

第二个就是找到ContentParent,这是个ViewGroup。

第三个就是把我们自己实现的布局转换成ViewTree,并且挂在ContentParent的下面,形成一个完整的activity的ViewTree。

相关推荐
服装学院的IT男2 小时前
【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
android
Arms2062 小时前
android 全面屏最底部栏沉浸式
android
服装学院的IT男2 小时前
【Android 源码分析】Activity生命周期之onStop-1
android
ChinaDragonDreamer5 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
网络研究院7 小时前
Android 安卓内存安全漏洞数量大幅下降的原因
android·安全·编程·安卓·内存·漏洞·技术
凉亭下7 小时前
android navigation 用法详细使用
android
小比卡丘10 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
前行的小黑炭11 小时前
一篇搞定Android 实现扫码支付:如何对接海外的第三方支付;项目中的真实经验分享;如何高效对接,高效开发
android
落落落sss12 小时前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
代码敲上天.13 小时前
数据库语句优化
android·数据库·adb