layoutInflater.inflate()
是常常运用的一个体系办法,运用它将XML
加载为一个View
目标,来详细扒一扒它的源码。
1. i单元测试nflate
inflate一共有四个重载方javaee法:
inflate(java模拟器int resource, ViewGroup root)
inflate(XmlPullParser parser, Vi源码交易平台ewGroup root)
inflate(int re源码中的图片source, ViewGroup root, boolean attachToRootjava语言)
infljava环境变量配置ate(XmlPu单元测试能发现约80的软件缺陷llParser parser, ViewGroup root, boolean attachToRoot)
前三个办法最终都调用到了第四个重载办法,不同的便是第三个办法中有一源码之家个tryIn变量值flatePelement是什么意思recompilJavaed()elements
办法,后续读取资源ID,转化为XmlResourjava编译器ceParse源码编辑器r
之后,还是调用了第四个重载办法,一java语言切的逻辑都是在第四个重载办法之中。
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
return inflate(parser, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
if (view != null) {
return view;
}
XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
进入t变量名的命名规矩elements中文翻译ry源码精灵永久兑换码InflelementanimationelementuiatePrecompiled()
查看这个办法会有一个if (!mUseCo源码网站mpiledView)
的退出判别。查这个变量的赋单元测单元测试家长评语试常用办法值的当地,默许的初始化办法是设置为fal变量名的命名规则se
,给它赋值为true
的当源码编辑器下载地只要一个,在setPrecompiledLayoutsEnabledForTesting()
,这是一个element滑板只针对单元测试开放的办法。
所以tryInflatePrecompiled()
办法一般不单元测试的主要内容会走到。
class LayoutInflater {
private boolean mUseCompiledView;
private void initPrecompiledViews() {
// Precompiled layouts are not supported in this release.
boolean enabled = false;
initPrecompiledViews(enabled);
}
private void initPrecompiledViews(boolean enablePrecompiledViews) {
mUseCompiledView = enablePrecompiledViews;
...
}
/**
* @hide for use by CTS tests
*/
@TestApi
public void setPrecompiledLayoutsEnabledForTesting(boolean enablePrecompiledLayouts) {
initPrecompiledViews(enablePrecompiledLayouts);
}
View tryInflatePrecompiled(int resource, Resources res, ViewGroup root, boolean attachToRoot) {
if (!mUseCompiledView) {
return null;
}
...
}
}
1.1. XmlResourcelement滑板eParser
前面经过调用res.getLayout(rejava训练source)
,变量泵将LayoutResjava编译器
转化为了XmlResourel源码中的图片ementanimationceParseelements中文翻译r
目标。
Xmlelements中文翻译ResourcePar源码网站ser
是XML资源的解析接口,简element翻译略来说便是一个XML变量的定义资源解析器,用于解析xml资源,在后面会大面积用到,这儿对它的办法源码编辑器做一些简略介绍。
-
int getEventType()
回来当时的事件类型,首要类型类型包括:单元测试
-
int START_DOCUMENT = 0
:XML文Ele源码编辑器下载ment单元测试的主要内容档开始标变量值志 -
int END_D单元测试常用方法OCUMENT = 1
:javascript变量与函数XML文档结束标志 -
injavaeet START_TAG = 2
:XML标签element滑板开始标志,比方<LinearLayout
。 -
int END_TA单元测试集成测试体系测试G = 3
:xml 标签结束标志,比方</LinearLayout>
或许/>
。
-
-
St变量名的命名规则ring gjava是什么意思etAttributeValue(String namespace,String name)
回来指定的特点名对应的elementui特点变量与函数值,假如没有运用命名空间,则第一个参数传入null。
-
String getNjavascriptame()
回来单元测试当时 TAG 的名字,变量名的命名规java面试题矩比方
<变量的界说;Lielementary是什么意思nearLayoutjava面试题
回来LinearLayout
。 -
int nextelement滑板()
光标移动到下一个标签。
-
int getDepth()
获取当时标签的深度,根布局深度为1,根Java布局的直接子控件深度为2 ,以此类推,每多一层深度加1。
1变量之间的关系.2. 第四个重载办法
这个办法中是inflate
的首要逻辑。
在这个办法中源码中的图片,首要是对merge
做了特别处理,直接调用了rInflate()
持续遍历。
merge
并不是一个ViewGroup
或许View
,它相当于声明晰一些视图等待被添加到另一个ViewGroup
中,能够削减许多不必要的布局。(运用merge
的时分能够运用tools:paren源码编辑器下载tTaelement滑板g
特点进行预览添加到对应ViewGroup
的效果)
关于不是merge
的状况,则调用Cr源码网站eateViewFromTag()
创立根视图之后,根视图将javaee作为root
调用rI源码之家nflateChildren()
持续遍历。这几个办法后文都有介绍。
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
。。。
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser); //特点调集
View result = root;
try {
//校验START_TAG标签
advanceToRootNode(parser);
final String name = parser.getName();
if (TAG_MERGE.equals(name)) {
//运用merge的时分,inflate必须有root且attachToRoot==true
if (root == null || !attachToRoot) {
throw new InflateException("<merge /> can be used only with a valid "
+ "ViewGroup root and attachToRoot=true");
}
rInflate(parser, root, inflaterContext, attrs, false);
} else {
//创立根视图
// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
//inflate的时分假如没有传root,给根view设置的特点会悉数失效
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)
//假如attachToRoot==false,直接将param设置给根视图
//假如attachToRoot==true,经过addView设置给根视图
temp.setLayoutParams(params);
}
}
// Inflate all children under temp against its context.
rInflateChildren(parser, temp, attrs, true);
// 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);
}
// Decide whether to return the root that was passed in or the
// top view found in xml.
//假如root != null && attachToRoot,会直接将root传回去,其他状况下将根视图传回去
if (root == null || !attachToRoot) {
result = temp;
}
}
}
return result;
}
}
接着从这个办法还能够Element看到平常运用infljava语言ate
的几个特性:
-
melementaryergejava编译器
并不是视图,对它设源码编变量之间的关系程器置的标签都是无效的 - 假如根布局是
merge
,运用inflate
加载时,root
不能为空且attchToRoot
不能是false
。 - 假如
root
为空,根视图的一切标签都将失单元测试常用方法效,原因应该是必须根据root
的类型源码中的图片去创立不同的layoutParam
。 - 假源码交易平台如
root != njava是什么意思ull && atta变量类型有哪些chT变量类型有哪些oRoot
,根视图会直接添加到root
,而且变量值relement翻译oot
将作为回来值,不然根源码编辑器视图作为回来值。
1.3. rInflate
接着往下看,rInelementaryfl单元测试家长评语ateChildren()
调用的还是rInflate()
办法,两个的差异也便是context
获取不太同。
rInflate()
中首单元测试用例先是一个大循环,看这个循环条件(源码编辑器(type = pelementanimationarser.n变量值ext()) != X源码之家mlPullParsejava面试题r.END_TAG ||parser.getDe变量值pth单元测试能发现约80的软件缺陷() > depthJava)
,只要两者同时不满足(即走到了END
标签,而且深度不大于parenelementst
的深度)才会退出循环element翻译,一般来说,也便是走到parent
的END_TAG
标签退出循环。
循环内部,对requestFocus
、tagelementary
、include
标签做了特别的处源码交易平台理,其他状况下调用createViewFromTag()
创立当时View
。而且调用rInflateChildrejava面试题n()
进行递归往下变量是什源码中的图片么意思调用。假如不是ViewGroup变量名
,会在源码编辑器下载下一次递java语言归中读取到当时view
的END_TAG
标签,也便是源码编辑器进不去循环之中java环境变量配置。
所源码之家以能够确定的是,每一层rInflatElemente()
调用的时源码网站候,创立出来的都只要parent
的直接子View
。最终创立出来的子源码view
都会被添加到对应的pa单元测试用例rent
。
final void rInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
rInflate(parser, parent, parent.getContext(), attrs, finishInflate);
}
void rInflate(XmlPullParser parser, View parent, Context context,
AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException {
final int depth = parser.getDepth();
int type;
boolean pendingRequestFocus = false;
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) {
//requestFocus:parent获得焦点
pendingRequestFocus = true;
consumeChildElements(parser); //跳过到parent层级
} else if (TAG_TAG.equals(name)) {
//tag: 调用parent.setTag(key, value)设置tag标签
parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {
//添加include 标签
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
//merge只能是根标签
throw new InflateException("<merge /> must be the root element");
} else {
// createViewFromTag创立view,然后持续深层遍历
final View view = createViewFromTag(parent, name, context, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
rInflateChildren(parser, view, attrs, true);
viewGroup.addView(view, params);
}
}
if (pendingRequestFocus) {
parent.restoreDefaultFocus();
}
if (finishInflate) {
parent.onFinishInflate();
}
}
1.4. cre单元测试变量之间的关系的首要内容ateViewFromT单元源码1688测试是什么ag
前面的办法中,多变量是什么意思次变量是什么意思经过调用crea单元测试家长评语teViewFromTag()
创立了控件。
这个办法中,首要特别处理变量是什么意思了view
标签,将clas源码编辑器s
途变量英语径作为name
读取出来。之后读取主题。
分为两步进行了测验创立,首要是调用tryCreateV源码编辑器下载iew()
进行创立。假如回来NULL
,接着判别途径名小数单元测试点的数量,分别走不同变量名的办法,回想一下,没有小数点的标签,也便elementary是什么意思是体系自带的各种view
,在XML中不需求输入全途径而只需elementary翻译求称号即可。
View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
boolean ignoreThemeAttr) {
if (name.equals("view")) {
//小写view,能够直接传入class途径,将name重置掉
name = attrs.getAttributeValue(null, "class");
}
//读取主题
if (!ignoreThemeAttr) {
final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
final int themeResId = ta.getResourceId(0, 0);
if (themeResId != 0) {
context = new ContextThemeWrapper(context, themeResId);
}
ta.recycle();
}
try {
View view = tryCreateView(parent, name, context, attrs);
if (view == null) {
...
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(context, parent, name, attrs);
} else {
view = createView(context, name, null, attrs);
}
}
}
return view;
}
...
}
1.4.1. tryCr源码编辑器下载eate源码1688View
接着看下怎么经过tryCreate变量英语View()
测验创立的。
办法首要判别blink
标签,elementanimation是留下java怎么读来的一个小彩蛋,Let’s party like变量泵 it’s 1995!
后续,调用mFactorelementary翻译y
,mFactory2Java
和mPrivat变量的定义eFactory
将源码之家创立办法代理出源码年代去。
public final View tryCreateView(@Nullable View parent, @NonNull String name,
@NonNull Context context,
@NonNull AttributeSet attrs) {
if (name.equals(TAG_1995)) {
// Let's party like it's 1995!
return new BlinkLayout(context, attrs);
}
View view;
if (mFactory2 != null) {
view = mFactory2.onCreateView(parent, name, context, attrs);
} else if (mFactory != null) {
view = mFactory.onCreateView(name, context, attrs);
} else {
view = null;
}
if (view == null && mPrivateFactory != null) {
view = mPrivateFactory.onCreateView(parent, name, context, attrs);
}
return view;
}
为了快速找到这几个工厂完成办法在javae变量名的命名规则e哪里,直接打个断点找一下。
能够看到,element变量ary首要调用的mFactory2
的完成AppCompatDelegateImpl
和mPrivat源码精灵永久兑换码eFactelement是什么意思ory
的完成Activielementaryty
。javascript
mPrivateFactory
的完成Activity
的逻辑会集在FragmentActivity
中,elementary是什么意思其间对fragjava怎样读ment
标签做特别处理,而且能够自己经过源码编程器Activity
去代理阻拦创立。这儿不向里边探索,首要来看下mFact单元测试能发现约80的软件缺陷ory2
的完成AppCjava培训ompatDelegateImpl
。
AppCompat变量名Delegatjava模拟器eImpl
中层层传递,最终在AppComelementanimationpatDelegateI单元测试mpl.createView()
中代理给了AppCompatViewInflater
实变量名现。
在AppCompatViewInflater.c源码编辑器reateView()
中能够看到,对标签为TextView
的直接创立回来了AppCompatTextView
。elementary翻译
这可elements不便是AppCompatXXX
之类的控件转化的当地!意外收成。也就搞清楚了,为什么XML
中就主动转化成对应的单元测试AppCompatXXX
,而自界说View
的变量值时分需求直接单元测试评语怎样写承继AppCom源码编程器patXXX
。
要是在这儿没有阻拦,一般就回来了NULL
,交由Layoutelement是什么意思Inelementary翻译flelementary是什么意思ater
创立。
//AppCompatDelegateImpl
public View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs) {
...
if (mAppCompatViewInflater == null) {
mAppCompatViewInflater = new AppCompatViewInflater();
...
}
return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,
IS_PRE_LOLLIPOP, /* Only read android:theme pre-L (L+ handles this anyway) */
true, /* Read read app:theme as a fallback at all times for legacy reasons */
VectorEnabledTintResources.shouldBeUsed() /* Only tint wrap the context if enabled */
);
}
//AppCompatViewInflater
final View createView(View parent, final String name, @NonNull Context context,
@NonNull AttributeSet attrs, boolean inheritContext,
boolean readAndroidTheme, boolean readAppTheme, boolean wrapContext) {
...
View view = null;
// We need to 'inject' our tint aware Views in place of the standard framework versions
switch (name) {
case "TextView":
view = createTextView(context, attrs);
verifyNotNull(view, name);
break;
case "ImageView":
view = createImageView(context, attrs);
verifyNotNull(view, name);
break;
...
}
return view;
}
//AppCompatViewInflater
protected AppCompatTextView createTextView(Context context, AttributeSet attrs) {
return new AppCompatTextView(context, attrs);
}
1.4.2. createV源码精灵永久兑换码iew
tryCreateView(变量之间的关系)
假如没有成功创立,会持续往下走,根据有没有小数点进入不同的onCreateView()
或许createView()
,首要单元测试能发现约80的软件缺陷来看下onCreateView()
是怎么处理体系控件的。
1.4.2.1. onjava是什么意思CreateView
在LayoutInflater
中,onCreateView()
也是层层传递,最终直接调用了createView
,只是将包名前缀android.vijava培训ewelementary.
作为perfix
特点带上进入了createView()
,看到这也就知道,之所以不变量之间的java培训关系需求写源码精灵永久兑换码完整包名,是因为java是什么意思主动进行了补充。
但走到这,有一个大疑惑源码交易平台,体系组件并不止android.view
这一个包名,查了一下单元测试中设计测试用例的根据是,发现LayoutInflater
有一个完成类PhoneLayou源码时代tInflater
重写了onCr变量英语eateView()
办法,在里边分别测验了android.widget
,androie变量名lements中文翻译d.webkit
和android变量与函数.app
的包名进行创源码年代建,也便是说,平常运用的LayoutInflater
其实是Ph变量的界说oneLayoutInflater
目标。
//LayoutInflater
protected View onCreateView(String name, AttributeSet attrs)
throws ClassNotFoundException {
return createView(name, "android.view.", attrs);
}
public class PhoneLayoutInflater extends android.view.LayoutInflater {
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit.",
"android.app."
};
@Override protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
for (String prefix : sClassPrefixList) {
try {
View view = createView(name, prefix, attrs);
if (view != null) {
return view;
}
}
}
return super.onCreateView(name, attrs);
}
}
1.4.2.2. createView
crea变量值teView()
终于看到了创立逻辑elements中文翻译,首要在缓存中查找有没有创立器。
假单元测试的主要内容如没有找到,就测验经过包名去加载CLASS
目标并拿到它的加载器缓存起来,这儿运用的便是刚才传入的prefix + name
,prefix
便是oncreate源码之家View()
中添加的完整包名前缀。
之后便是调用newInstance()
创立单元测试目标,传入的参数Object[]
,共有两位,第一位是Context
,第二位是AttrelementsibuteSet
。对应的便是View(Context context, AttributeSet attrs)
结构办法。这儿也就对应了假如自界说Vieelementsw
只是完成了Conte单元测试xt单元测试
的结构办法,代码中动态Element创立不会单元测试犯错,可是不能在XML
运用。
另一个点,便是这儿反射并没有更改访问权限的检查,所以JAVA
中需求给CLASS
设置public
(Kotlin
中默许是elementuip单元测试是什么ublic
=_=)。
public final View createView(NonNull Context viewContext, NonNull String name,
@Nullable String prefix, @Nullable AttributeSet attrs)
throws ClassNotFoundException, InflateException {
...
Constructor<? extends View> constructor = sConstructorMap.get(name);
if (constructor != null && !verifyClassLoader(constructor)) {
constructor = null;
sConstructorMap.remove(name);
}
Class<? extends View> clazz = null;
try {
if (constructor == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
mContext.getClassLoader()).asSubclass(View.class);
constructor = clazz.getConstructor(mConstructorSignature);
constructor.setAccessible(true);
sConstructorMap.put(name, constructor);
}
Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = viewContext;
Object[] args = mConstructorArgs;
args[1] = attrs;
try {
final View view = constructor.newInstance(args);
return view;
} finally {
mConstructorArgs[0] = lastContext;
}
}
...
}
1.5. parseIncelementanimatio源码精灵永久兑换码nlude
前面看到过,关于include
标签做了element滑板特别处理单元测试家长评语。
逻辑和inflate
根本一致,读取到了layout
的id
之后,先调用源码网站tryInfl变量ate源码交易平台Precompiled()
,之前介绍过这个办法只是为了测试用。
然后java模拟器根据是不是merge
标签,走element滑板不同源码的分支进入到rInflate()
,进入创立流程。
private void parseInclude(XmlPullParser parser, Context context, View parent,
AttributeSet attrs) throws XmlPullParserException, IOException {
int type;
int layout = attrs.getAttributeResourceValue(null, ATTR_LAYOUT, 0);
...
final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
(ViewGroup) parent, /*attachToRoot=*/true);
if (precompiled == null) {
final XmlResourceParser childParser = context.getResources().getLayout(layout);
try {
...
if (TAG_MERGE.equals(childName)) {
rInflate(childParser, parent, context, childAttrs, false);
} else {
final View view = createViewFromTag(parent, childName,
context, childAttrs, hasThemeOverride);
final ViewGroup group = (ViewGroup) parent;
// Inflate all children.
rInflateChildren(childParser, view, childAttrs, true);
...
group.addView(view);
}
} finally {
childParser.close();
}
}
}
2. Inflaelement滑板te获取
-
经过体系服务获变量是什么意思取
LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
经过
f变量英语rom
获取LayoutInflater
静态办法获取,也是经过体系服务获取。public static LayoutInflater from(Context context) { LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (LayoutInflater == null) { throw new AssertionError("LayoutInflater not found."); } return LayoutInflater; }
-
经过
activity
获取java语言acti单元测试家长评语vity
从PhoneWindow
中获取,PhoneWindow
中也是经过from
获取。public LayoutInflater getLayoutInflater() { return getWindow().getLayoutInflater(); } public class PhoneWindow extends Window implements MenuBuilder.Callback { private LayoutInflater mLayoutInflater; public PhoneWindow(Context context) { super(context); mLayoutInflater = LayoutInflater.from(context); } public LayoutInflater getLayoutInflater() { return mLayoutInflater; } }
-
经过
View
获取View
留有infl变量泵ate
办法,经过from
获取LayoutInflater
。public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { LayoutInflater factory = LayoutInflater.from(context); return factory.inflate(resource, root); }
假如觉得这篇文章不错,请点个赞支elementary是什么意思撑一下。