android进阶篇14、UI布局层次结构及布局加载流程源码解析

public Window getWindow() {
return mWindow; //2
}

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) {
attachBaseContext(context);

mWindow = new PhoneWindow(this, window, activityConfigCallback); //3
、、、
}

2、mWindow.setContentView(layoutResID)

通过上面我们知道最终调用的是PhoneWindow的setContentView,方法如下所示,主要干了两件事情,注释1用于生成DecorView和mContentParent;注释2处用于将layoutResID(也就是我们实现的布局id)设置到mContentParent中去;

public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor(); //1
}
、、、
mLayoutInflater.inflate(layoutResID, mContentParent);//2
、、、
}

3、installDecor()

installDecor方法代码如下所示,注释1处通过generateDecor方法生成mDecor变量,generateDecor方法内部其实就是new了一个DecorView;注释2处通过generateLayout方法获得mContentParent;mDecor是PhoneWindow的成员变量,是DecorView类型的,继承自FrameLayout;而这个mContentParent代表mDecor本身或者mDecor的子布局,什么意思呢?其实在mDecor的上部有一个占位View,根据不同的主题加载不同的DecorView,如果没有加载顶部view那mContentParent就是mDecor了;

private void installDecor() {
、、、
mDecor = generateDecor(-1); //1
、、、
mDecor.setWindow(this);
、、、
mContentParent = generateLayout(mDecor); //2
}

4、布局层次

经过上面的分析,我们发现Activity持有一个PhoneWindow的成员变量;PhoneWindow持有一个DecorView的成员变量,DecorView内部持有一个mContentParent,所以布局层次结构就是 Activity – PhoneWindow – DecorView – mContentParent;

而我们写的xml布局就是放在了mContentParent中;那么xml布局是如何加载到mContentParent容器的呢?其实也就是步骤2的注释2的mLayoutInflater.inflate(layoutResID, mContentParent)进行加载的,我们在下一部分分析加载的流程;

二、布局加载流程分析

1、mLayoutInflater.inflate(layoutResID, mContentParent)的调用链如下所示;

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null); //1
}

public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot); //2
} finally {
parser.close();
}
}

2、最终会调用到如下inflate方法,注释1处将root赋值给result;注释2处会通过createViewFromTag创建根View;注释4处用于inflate所有的children;这里解释一下最后一个attachToRoot参数,如果设置为true,会调用注释5将根view添加到root中然后将root返回;如果设置为false,会调用到注释3处,将root的参数设置到根view中去,但并不会执行addView操作,然后调用到注释6处将根view赋值给result,这样返回的就是根view而不是root;

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
View result = root; //1

final String name = parser.getName();

// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs); //2

ViewGroup.LayoutParams params = null;

if (root != null) {

// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// Set the layout params for temp if we are not
// attaching. (If we are, we use addView, below)
temp.setLayoutParams(params); //3
}
}

// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true); //4

// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params); //5
}

// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp; //6
}
return result;
}

3、通过createViewFromTag创建根view,此方法调用链如下所示;注释1处是第一次创建view;注释2和注释3最终都会调用到注释3处的方法;注释1是一种情况,注释3是另一种情况,我们分别讨论一下;

private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs) {
return createViewFromTag(parent, name, context, attrs, false);
}

View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
boolean ignoreThemeAttr) {

View view = tryCreateView(parent, name, context, attrs); //1

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

总结

可以看出,笔者的工作学习模式便是由以下 「六个要点」 组成:

❝ 多层次的工作/学习计划 + 番茄工作法 + 定额工作法 + 批处理 + 多任务并行 + 图层工作法❞

希望大家能将这些要点融入自己的工作学习当中,我相信一定会工作与学习地更富有成效。

下面是我学习用到的一些书籍学习导图,以及系统的学习资料。每一个知识点,都有对应的导图,学习的资料,视频,面试题目。

**如:我需要学习 **Flutter的知识。(大家可以参考我的学习方法)

点击这里了解更多即可领取!
  • Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)

  • Flutter进阶学习全套手册

  • Flutter进阶学习全套视频

g-82vy8JgV-1710572897647)]

  • Flutter进阶学习全套手册

[外链图片转存中…(img-6D54yFOv-1710572897647)]

  • Flutter进阶学习全套视频

[外链图片转存中…(img-xjpdwL2z-1710572897648)]

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

  • 27
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的 Android 设置界面的布局源代码,其中包括一个 ListView 和一些简单的布局元素: ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- 标题 --> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Settings" android:textSize="24sp" android:padding="16dp"/> <!-- 列表 --> <ListView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:divider="@null" android:dividerHeight="0dp"/> <!-- 底部按钮 --> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="16dp"> <Button android:id="@+id/save_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Save"/> <Button android:id="@+id/cancel_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cancel"/> </LinearLayout> </LinearLayout> ``` 你可以将这个布局文件命名为 `app_set_activity.xml`,并将其放置在你的 Android 项目的 `res/layout` 目录中。然后,你可以在代码中使用以下代码来加载这个布局: ```java public class AppSetActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.app_set_activity); // TODO: 在这里添加你的代码 } } ``` 注意,这个布局只是一个示例,你可以根据你的需要进行更改和定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值