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

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui