深入理解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。

相关推荐
数据猎手小k1 小时前
AndroidLab:一个系统化的Android代理框架,包含操作环境和可复现的基准测试,支持大型语言模型和多模态模型。
android·人工智能·机器学习·语言模型
你的小102 小时前
JavaWeb项目-----博客系统
android
风和先行2 小时前
adb 命令查看设备存储占用情况
android·adb
AaVictory.3 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
似霰4 小时前
安卓智能指针sp、wp、RefBase浅析
android·c++·binder
大风起兮云飞扬丶4 小时前
Android——网络请求
android
干一行,爱一行4 小时前
android camera data -> surface 显示
android
断墨先生4 小时前
uniapp—android原生插件开发(3Android真机调试)
android·uni-app
无极程序员6 小时前
PHP常量
android·ide·android studio
萌面小侠Plus7 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机