如何应对Android面试官->布局原理与xml解析,手写插件化换肤框架核心实现(上)

前言

本节内容分为上下两章,上章主要介绍布局流程和 xml 解析流程,下章带着大家手写插件化换肤框架的核心实现;

布局流程

想要布局,我们必须要启动 Activity 然后才能进行布局的渲染操作,启动 Activity 我们可以通过 ActivityThread 的 performLaunchActivity 看起,本章不详解 Activity 的启动流程,感兴趣的可以关注我,在 FrameWork 系列我后面会详细讲解,所以 我们进入 performLaunchActivity 方法看下:

 

typescript

复制代码

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // ... // 省略部分代码 // 创建 Activity activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); if (activity != null) { Window window = null; if (r.mPendingRemoveWindow != null && r.mPreserveWindow) { window = r.mPendingRemoveWindow; } // ... // 省略部分代码 // 可以看到,attach 的时候,将 window 传递了过去,我们去 attach 看下 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config, r.referrer, r.voiceInteractor, window, r.configCallback, r.assistToken); } }

进入 Activity 的 attach 方法看下:

 

arduino

复制代码

final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config, String referrer, IVoiceInteractor voiceInteractor, Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) { // ... // 省略部分代码 // window 在 attach 方法里进行了 初始化 mWindow = new PhoneWindow(this, window, activityConfigCallback); // ... // 省略部分代码 }

也就是说 Activity 中 持有着一个 PhoneWindow,这里建立了 Activity 和 Window 的关联;

当 Activity 执行 onCreate 的时候,我们需要调用 setContentView 设置布局,这个setContentView 就是 PhoneWindow 提供的一个方法,我们进入这个方法看下:

 

scss

复制代码

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; }

setContentView 方法中主要关注两个方法的调用,installDecor() 和 mLayoutInflater.inflate();

首先我们来看下 installDecor 都干了什么?

installDecor

 

scss

复制代码

private void installDecor() { // ... // 省略部分代码 if (mDecor == null) { mDecor = generateDecor(-1); mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); } else { mDecor.setWindow(this); } // 使用 DecorView 生成布局 if (mContentParent == null) { mContentParent = generateLayout(mDecor); } // ... // 省略部分代码 }

如果 mDecor 为空,就调用 generateDecor 方法,进行创建,我们进入这个方法看一下:

generateDecor

 

scss

复制代码

protected DecorView generateDecor(int featureId) { // System process doesn't have application context and in that case we need to directly use // the context we have. Otherwise we want the application context, so we don't cling to the // activity. Context context; if (mUseDecorContext) { Context applicationContext = getContext().getApplicationContext(); if (applicationContext == null) { context = getContext(); } else { context = new DecorContext(a

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值