从源码角度分析Activity#setContentView

本文从源码角度详细分析了Android中Activity#setContentView的执行流程,涉及PhoneWindow、DecorView和layout渲染。通过源码解读,揭示了如何将布局资源解析并添加到DecorView的主容器中,帮助理解Android界面绘制的本质。

我们平时在开发的过程中将一个layout绘制出来是通过Activity#setContentView或者AppCompactActivity#setContentView,本文只分析Activity#setContentView,AppCompactActivity#setContentView可通过我的另外一篇文章了解 从源码角度分析AppCompactActivity#setContentView

先来看看源码执行的流程图
在这里插入图片描述

有了上面的流程图我们对就setContentView源码调用有了个大概的框架,再来分析源码就不会小鹿乱撞了,哈哈,现在从setContentView入手来看整个绘制流程源码

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

我们点进去setContentView看看源码

    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }

这里的getWindow()返回的是Window的唯一实现类PhoneWindow,继续跟进PhoneWindow#setContentView

@Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

这里面先调用installDecor(),然后判断有无转场动画,有转场动画执行专场动画,最终都通过LayoutInflater解析传进来的layoutResID到mContentParent,继续跟进installDecor()

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            // 注释1
            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) {
            // 注释2
            mContentParent = generateLayout(mDecor);

            // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
            mDecor.makeOptionalFitsSystemWindows();

            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                    R.id.decor_content_parent);

            if (decorContentParent != null) {
                mDecorContentParent = decorContentParent;
                mDecorContentParent.setWindowCallback(getCallback());
                if (mDecorContentParent.getTitle() == null) {
                    mDecorContentParent.setWindowTitle(mTitle);
                }

                final int localFeatures = getLocalFeatures();
                for (int i = 0; i < FEATURE_MAX; i++) {
                    if ((localFeatures & (1 << i)) != 0) {
                        mDecorContentParent.initFeature(i);
                    }
                }

                mDecorContentParent.setUiOptions(mUiOptions);

                if ((
<think>我们聚焦于从源码角度分析Activity启动流程,主要环节如下: ### 1. **Launcher发起启动请求** - **入口**:`Launcher`点击应用图标触发`startActivity()` - **关键调用链**: ```java // frameworks/base/core/java/android/app/Activity.java public void startActivity(Intent intent) { mInstrumentation.execStartActivity(...); // 通过Instrumentation发起 } ``` - **跨进程通信**:通过Binder调用到`ActivityTaskManagerService` (ATMS)[^1] ### 2. **ATMS处理启动请求** - **核心逻辑**:`frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java` ```java class ActivityTaskManagerService { int startActivity(...) { return getActivityStartController().obtainStarter(...).execute(); } } ``` - **关键步骤**: - 验证权限及Intent - 创建`ActivityRecord`对象记录Activity信息 - 决策是否新建进程[^1][^2] ### 3. **进程创建(若需新建)** - **调用路径**: ``` ATMS.startProcessAsync() → LocalService.startProcess() → ProcessList.startProcessLocked() ``` - **Zygote孵化**: ```java // frameworks/base/services/core/java/com/android/server/am/ProcessList.java final Process.ProcessStartResult startResult = Process.start(...); ``` - 通过Socket连接Zygote fork新进程[^1] ### 4. **目标进程初始化** - **入口**:`ActivityThread.main()` ```java // frameworks/base/core/java/android/app/ActivityThread.java public static void main(String[] args) { Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); // 绑定到AMS Looper.loop(); } ``` - **绑定系统服务**:通过`ApplicationThread` Binder对象与ATMS通信[^3] ### 5. **Activity实例化与生命周期** - **ATMS回调**:`ApplicationThread.scheduleLaunchActivity()` - **核心处理**: ```java // ActivityThread.handleLaunchActivity() final Activity a = performLaunchActivity(r, customIntent); if (a != null) { handleResumeActivity(...); // 触发onResume() } ``` - **关键源码**: ```java // ActivityThread.performLaunchActivity() Activity activity = mInstrumentation.newActivity(...); // 反射创建实例 Application app = r.packageInfo.makeApplication(...); // 创建Application activity.attach(...); // 关联Context mInstrumentation.callActivityOnCreate(activity, ...); // 回调onCreate() ``` - **视图渲染**:`onCreate()`中调用`setContentView()`触发DecorView创建[^3] ### 6. **界面绘制与显示** - **首帧同步**:`handleResumeActivity()`中触发View绘制 ```java // ActivityThread.handleResumeActivity() wm.addView(decor, layoutParams); // 添加DecorView到WindowManager ``` - **VSync同步流程**: 1. `ViewRootImpl.scheduleTraversals()`请求VSync信号 2. Choreographer通过SF进程同步VSync 3. 收到VSync后执行`performTraversals()`(测量/布局/绘制)[^3] ### 性能优化关键点 1. **进程复用**:通过`android:process`共享进程减少fork开销 2. **异步加载**:在`onCreate()`中延迟加载非必要资源 3. **渲染优化**:使用`<merge>`标签减少视图层级 4. **冷启动加速**:借助StartingWindow展示预览界面 --- §§相关问题§§ 1. `Instrumentation`在Activity启动中承担什么角色? 2. Zygote孵化新进程时如何复制内存页? 3. `ViewRootImpl.performTraversals()`的测量-布局-绘制三个阶段如何协同工作? </think>以下是从源码角度分析的Android Activity启动主要流程环节,涵盖从Launcher点击到界面渲染的核心过程: --- ### 1. **Launcher发起启动请求** - **入口**:`Launcher.onClick()` (packages/apps/Launcher3) - **关键调用链**: ```java // Launcher.java onClick(View v) { startActivitySafely(v, intent, item); // 启动目标应用 } → startActivity(intent) → Instrumentation.execStartActivity() // 跨进程通信枢纽 ``` - **跨进程通信**:通过Binder调用`ActivityTaskManagerService` (ATMS)[^1] --- ### 2. **ATMS处理启动请求** - **核心逻辑**:`ActivityTaskManagerService.startActivity()` ```java // frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java public int startActivity(...) { return getActivityStartController().obtainStarter(intent).execute(); } ``` - **关键步骤**: 1. 解析Intent获取目标Activity信息 2. 检查权限及进程状态 3. 决策是否需创建新进程(`ProcessRecord`) 4. 创建`ActivityRecord`对象[^1] --- ### 3. **进程创建(若需新建)** - **Zygote孵化流程**: ```java // frameworks/base/services/core/java/com/android/server/am/ProcessList.java final Process.ProcessStartResult startResult = Process.start(...); ``` - 通过Socket联系Zygote - fork新进程并执行`ActivityThread.main()` - **内存优化**:Copy-on-Write复用Zygote预加载资源[^1] --- ### 4. **目标进程初始化** - **入口**:`ActivityThread.main()` ```java // frameworks/base/core/java/android/app/ActivityThread.java public static void main(String[] args) { Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); // 绑定到AMS Looper.loop(); } ``` - **关键动作**: - 创建`ApplicationThread` Binder对象 - 通过`ATTACH_APPLICATION`消息注册到AMS[^3] --- ### 5. **Activity实例化与生命周期** - **ATMS回调**:`ApplicationThread.scheduleLaunchActivity()` - **核心处理**: ```java // ActivityThread.handleLaunchActivity() private void handleLaunchActivity(...) { final Activity a = performLaunchActivity(r, customIntent); // 创建实例 handleResumeActivity(...); // 触发onResume() } ``` - **创建细节**: ```java // performLaunchActivity() Activity activity = mInstrumentation.newActivity(...); // 反射创建 Application app = r.packageInfo.makeApplication(...); // 创建Application activity.attach(...); // 关联Context mInstrumentation.callActivityOnCreate(activity, ...); // 回调onCreate() ``` - **视图初始化**:`onCreate()`中调用`setContentView()`触发DecorView创建[^3] --- ### 6. **界面绘制与显示** - **添加到窗口**:`ActivityThread.handleResumeActivity()` ```java wm.addView(decor, layoutParams); // 添加DecorView到WindowManager ``` - **VSync同步绘制**: 1. `ViewRootImpl.scheduleTraversals()`请求VSync信号 2. Choreographer通过`FrameDisplayEventReceiver`接收VSync 3. 执行`performTraversals()`(测量/布局/绘制) 4. SurfaceFlinger合成帧缓存[^3] --- ### 性能优化关键点 1. **进程复用**:通过`android:process`共享进程减少fork开销 2. **异步加载**:在`onCreate()`中延迟初始化非必要资源 3. **渲染管线优化**: ```java // 启用硬件加速 <activity android:hardwareAccelerated="true"/> ``` 4. **冷启动优化**:使用SplashScreen API展示即时预览 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值