先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
正文
}
}
这里我们看到,通过层层调用,最终会调用到 LayoutInflator#inflate(int, ViewGroup, boolean) 方法,很明显,这个方法会将我们传入的布局 id 转换为 XmlResourceParser,然后进行另一次,也是最后一次重载。
这个方法就厉害了,这里基本上包括了我们所有问题的答案,我们继续往下看。
话不多说,上代码。接下来我们来逐段分析下这个 inflate 方法:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
// 默认返回结果为传入的根布局
View result = root;
// 通过 createViewFromTag() 方法找到传入的 layoutId 的根布局,并赋值给 temp
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
// 如果传入的父布局不为空
if (root != null) {
// 为这个 root 生成一套合适的 LayoutParams
params = root.generateLayoutParams(attrs);
if (!attachToRoot) {
// 如果没有 attachToRoot,那为根布局设置 layoutparams
temp.setLayoutParams(params);
}
}
// 如果传入的父布局不为空,且想要 attachToRoot
if (root != null && attachToRoot) {
// 那就将传入的布局以及 layoutparams 通过 addView 方法添加到父布局中
root.addView(temp, params);
}
// 如果传入的根布局为空,或者不想 attachToRoot,则返回要加载的 layoutId
if (root == null || !attachToRoot) {
result = temp;
}
return result;
}
代码也分析完了,我再来总结一下:
-
View#inflate 只是个简易的包装方法,实际上还是调用的 LayoutInflater#inflate ;
-
LayoutInflater#inflate 由于可以自己选择 root 和 attachToRoot
的搭配(后面有解释),使用起来更加灵活;
-
实际上的区别只是在于 root 是否传空,以及 attachToRoot 真假与否;
-
当 root 传空时,会直接返回要加载的 layoutId,返回的 View 没有父布局且没有 LayoutParams;
-
当 root 不传空时,又分为 attachToRoot 为真或者为假:
-
attachToRoot = true 会为传入的 layoutId 直接设置参数,并将其添加到 root 中,然后将传入的 root
返回;
- attachToRoot = false 会为传入的 layoutId 设置参数,但是不会添加到 root ,然后返回 layoutId
对应的 View;
这里需要注意的是,虽然不马上将 View 添加到 parent 中,但是这里最好也传上 parent,而不是粗暴的传入 null;因为子
View 的 LayoutParams 需要由 parent 来确定;否则会在手动 addView 时调用
generateDefaultLayoutParams() 为子 View 生成一个宽高都为包裹内容的
LayoutParams,而这并不一定是我们想要的。
单说起来可能有些抽象,下面使用代码来进行具体的测试与检验。
View.inflate(context, layoutId, null)
如之前所说,这实际上调用的是 getLayoutInflater().inflate(layoutId, null) ,结合之前的源码来看:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
View result = root;
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
if (root == null || !attachToRoot) {
result = temp;
}
return result;
}
很明显,传入的 root 为空,则会直接将加载好的 xml 布局返回,而这种情况下返回的这个 View 没有参数,也没有父布局。
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
View inflateView = View.inflate(this, R.layout.layout_basic_use_item, null);
Log.e(“Test”, "LayoutParams -> " + inflateView.getLayoutParams());
Log.e(“Test”, "Parent -> " + inflateView.getParent());
}
如图所示,正如我们想的,root 传 null 时,参数以及父布局返回结果均为 null。
View.inflate(context, layoutId, mParent)
按之前分析过的,此方法实际调用的是 getLayoutInflater().inflate(layoutId, root, true) ,再来看源码:
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
View result = root;
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
params = root.generateLayoutParams(attrs);
}
if (root != null && attachToRoot) {
root.addView(temp, params);
}
return result;
}
如源码所示,返回的 result 会在最开始就被赋值为入参的 root,root 不为空,同时 attachToRoot 为 true,就会将加载好的布局直接通过 addView 方法添加到 root 布局中,然后将 root 返回。
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
LinearLayout mParent = findViewById(R.id.ll_root);
View inflateView = View.inflate(this, R.layout.layout_basic_use_item, mParent);
Log.e(“Test”, "LayoutParams -> " + inflateView.getLayoutParams());
Log.e(“Test”, "Parent -> " + inflateView.getParent());
Log.e(“Test”, "inflateView -> " + inflateView);
}
如图示,返回的 View 正是我们传入的 mParent,对应的 id 是 ll_root,参数也不再为空。
getLayoutInflater().inflate(layoutId, root, false)
也许会有人问了,现在要么是 root 传空,返回 layoutId 对应的布局;要么是 root 不传空,返回传入的 root 布局。那我要是想 root 不传空,但是还是返回 layoutId 对应的布局呢?
这就是 View#inflate 的局限了,由于它是包装方法,因此 attachToRoot 并不能因需定制。这时候我们完全可以自己调用 getLayoutInflater().inflate(layoutId, root, false) 方法,手动的将第三个参数传为 false,同时为这个方法传入目标根布局。这样,我们就可以得到一个有 LayoutParams,但是没有 parentView 的 layoutId 布局了。
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_test);
LinearLayout mParent = findViewById(R.id.ll_root);
View inflateView = getLayoutInflater().inflate(R.layout.main, mParent, false);
Log.e(“Test”, "LayoutParams -> " + inflateView.getLayoutParams());
Log.e(“Test”, "Parent -> " + inflateView.getParent());
}
尾声
面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Android核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、热修复设计、插件化框架解读、组件化框架设计、图片加载框架、网络、设计模式、设计思想与代码质量优化、程序性能优化、开发效率优化、设计模式、负载均衡、算法、数据结构、高级UI晋升、Framework内核解析、Android组件内核等。
不仅有学习文档,视频+笔记提高学习效率,还能稳固你的知识,形成良好的系统的知识体系。这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
大厂面试真题
PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)
《2017-2021字节跳动Android面试历年真题解析》
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-EmrrrNxh-1713621102702)]
《2017-2021字节跳动Android面试历年真题解析》
[外链图片转存中…(img-XXPxu7AV-1713621102702)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-vOCzsMC2-1713621102703)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!