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

相关推荐
百锦再5 小时前
低代码开发的约束性及ABP框架的实践解析
android·开发语言·python·低代码·django·virtualenv·rxjava
那我掉的头发算什么6 小时前
【数据库】navicat的下载以及数据库约束
android·数据库·数据仓库·sql·mysql·数据库开发·数据库架构
明道源码6 小时前
Android Studio 应用运行到真机设备
android·ide·android studio
生莫甲鲁浪戴6 小时前
Android Studio新手开发第二十五天
android·ide·android studio
Varpb7 小时前
android studio-设置android模拟器屏幕自动旋转
android·android studio
2501_915106328 小时前
iOS 打包 IPA 全流程详解,签名配置、工具选择与跨平台上传实战指南
android·macos·ios·小程序·uni-app·cocoa·iphone
超低空8 小时前
Android MediaSession深度解析:车载音乐播放器完整案例
android·架构·客户端
QmDeve8 小时前
Android 集成与使用模糊开关按钮视图 (BlurSwitchButtonView)
android·github
00后程序员张8 小时前
iOS 混淆实操指南多工具组合实现 IPA 混淆、加固与发布治理 IPA 加固
android·ios·小程序·https·uni-app·iphone·webview
xiaoshiquan12069 小时前
as强制过滤指定依赖版本库,解决该依赖不同版本冲突
android