文章目录
在 (4.4.3)android的布局类中讲到了 LayoutInflater 的用法
//1. 调用LayoutInflater静态from方法,获取LayoutInflater对象,然后调用其inflate方法获取一个View对象
public static LayoutInflater from(Context context)
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)
//2. 调用View的静态inflate方法,获取对象,不过该方法其实等同于封装了方式1。
public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
LayoutInflater factory = LayoutInflater.from(context);
return factory.inflate(resource, root);
}
我们解答以下问题:
-
每次调用LayoutInflater的from方法都会创建一个新的LayoutInflater对象吗?
- 调动LayoutInflater的from方法实际上创建的是它的子类 PhoneLayoutInflater 对象,根据入参的上下文对象只clone出一个
-
LayoutInflater的from方法中如果传递不同的Context对象会有什么不同?
- 我们通过LayoutInflater的from(Context context)方法获取一个LayoutInflater对象,传递不同的Context对象,获取到的LayoutInflater对象也不同。
- 每一个Activity 都会持有一个 LayoutInflater 对象, 如果每次传递的Context对象都是同一个Activity 对象,只会创建一个 LayoutInflater 对象。
- 每一个Application也会持有一个LayoutInflater 对象
-
调用View的getContext() 方法会获取一个Context,那么这个Context对象具体是谁呢?
- 构建LayoutInflater时传入的上下文对象
-
为什么想要在xml中使用View,就必须要有两个参数的构造方法呢?
- 因为LayoutInflater.createview最终反射构造视图实例时,传入的对象就是两个参数
-
LayoutInflater对象的真正创建时机是什么时候?
- Acivity的onAttach中创建PhoteWIndows时,会通过 context.getSystemService获取到
-
Fragment中有一个onCreateView方法,有一个参数是LayoutInflater,这么LayoutInflater对象是从哪来的呢?
- FragmentManage最终调用Fragment的performCreateView, 并最终通过mContext.getSystemService获取
一、From方法是怎么构造LayoutInflater
- ContextThemeWrapper#getSystemService(xx)
- 针对inflateservice封装了一层
- 先获取自己的成员实例mInflater,有则直接返回
- 如果没有的话用base.getSystemService(xx)拿到唯一的,并用cloneInContext(组件实例)方法浅复制一份封装成PhoneLayoutInflater
- ContexWrapper#getSystemService(xx)
- 直接使用base.getSystemService(xx)
- Contextlmpl#getSystemService(xx)
- 会真实的从远程服务对象处构建一个layoutinflate,这个是全局唯一的
,下次访问就返回缓存中的这个对象
- 会真实的从远程服务对象处构建一个layoutinflate,这个是全局唯一的
1.1 源码分析
#android.view.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;
}
1.1.1 ContextThemeWrapper: Activity.getSystemService(LAYOUT_INFLATER_SERVICE)
- 可以看到调用了Context的getSystemService方法,如果我们传递的是Activity,会先调用Activity的getSystemService() 方法
# android.app.Activity
@Override
public Object getSystemService(@ServiceName @NonNull String name) {
if (getBaseContext() == null) {
throw new IllegalStateException(
"System services not available to Activities before onCreate()");
}
if (WINDOW_SERVICE.equals(name)) {
return mWindowManager;
} else if (SEARCH_SERVICE.equals(name)) {
ensureSearchManager();
return mSearchManager;
}
return super.getSystemService(name);
}
- Activity 中的 getSystemService() 方法只是对 WINDOW_SERVICE 和 SEARCH_SERVICE 做了单独的处理,没有对 LAYOUT_INFLATER_SERVICE 做什么处理,不过Activity是继承自 ContextThemeWrapper 的,我们再来看一下ContextThemeWrapper 的 getSystemService() 方法。
#android.view.ContextThemeWrapper
@Override
public Object getSystemService(String name) {
if (LAYOUT_INFLATER_SERVICE.equals(name)) {
if (mInflater == null) {
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);//1
}
return mInflater;
}
return getBaseContext().getSystemService(name);
}
- 如果我们获取LayoutInflater对象,并且当前的 mInflater 变量为空的话就会调用1处的 LayoutInflater.from(getBaseContext()).cloneInContext(this) 方法创建一个LayoutInflater对象,下次再调用的时候直接返回这个对象,不会重复创建。
- 上面的代码中getBaseContext()方法获取的就是该Activity绑定的mBase对象,这个mBase是一个Context对象 ,但Context是一个抽象类
1.2 ContextWrapper: Application.getSystemService(LAYOUT_INFLATER_SERVICE)
Application是继承自ContextWrapper的,来看一下ContextWrapper的 getSystemService() 方法。
# android.content.ContextWrapper
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
直接调用了 mBase 的 getSystemService() 方法
1.3 ContextImpl
这个mBase就是一个ContextImpl对象。Application、Activity、Service对象在创建完毕之后他们的attach() 方法都会被调用,在 attach() 中会调用 attachBaseContext() 方法,就会给这个mBase 赋值,实际上是一个 ContextImpl对象
- 通过上面的分析我们会发现,不管是传递Activity还是Application实际上都会先调用ContextImpl 的 getSystemService() 方法,直接来看一下它:
# android.app.ContextImpl
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
- ContextImpl 调用了 SystemServiceRegistry的getSystemService() 方法,需要说明一点,ContextImpl 的getSystemService() 方法在不同的版本中都会有不同。我们不需要纠结API的不同,侧重流程,看到我们想要看的即可。比如现在,我们想要看的是LayoutInflater对象是怎么创建的,跟着代码继续看 SystemServiceRegistry的getSystemService() 方法。
# android.app.SystemServiceRegistry
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
- 在 SystemServiceRegistry的getSystemService() 方法中通过一个 SYSTEM_SERVICE_FETCHERS 来根据一个 name 获取一个 ServiceFetcher 对象,然后调用它的getService 返回一个对象
- 我们的LayoutInflater 对象应该就是通过ServiceFetcher 获得
- SYSTEM_SERVICE_FETCHERS 实际上就是一个HashMap
- SystemServiceRegistry这个类都是静态方法和静态代码块,也就是说只要这个类加载的时候就会触发注册,SystemServiceRegistry注册了App运行需要用到的所有服务,有AMS,PMS、NMS,我们需要用到 LAYOUT_INFLATER_SERVICE 也就是LayoutInflater 也在其中。
- ServiceFetcher的getService中首先会看看当前是否已经缓存了对应的对象,比如我们想要获取的LayoutInflater,如果已经有的话会直接返回这个对象,如果没有的话就会调用其createService() 方法
final class SystemServiceRegistry {
private static final String TAG = "SystemServiceRegistry";
// Service registry information.
// This information is never changed once static initialization has completed.
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
new HashMap<Class<?>, String>();
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
private static int sServiceCacheSize;
// Not instantiable.
private SystemServiceRegistry() { }
static {
...
registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
new CachedServiceFetcher<ActivityManager>() {
@Override
public ActivityManager createService(ContextImpl ctx) {
return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
}});
...
registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
new CachedServiceFetcher<LayoutInflater>() {
@Override
public LayoutInflater createService(ContextImpl ctx) {
return new PhoneLayoutInflater(ctx.getOuterContext());
}});
...
}
- 通过PhoneLayoutInflater 的一个参数的构造方法创建了LayoutInflater 对象。
通过上面的分析我们也可以发现
- 不管是LayoutInflater的from方法中的 Context,传递Activity还是Application实际上都会先调用ContextImpl 的 getSystemService() 方法获取一个LayoutInflate
- 这个对象是唯一的,只要是从ContextImpl这获取的,就只有一个
- 对于Activity不同的是又调用了 cloneInContext() 方法来获取一个LayoutInflater对象,看上去好像是一个新的对象
1.4 cloneInContext 和 getOuterContext
对于Activity不同的是又调用了 cloneInContext() 方法来获取一个LayoutInflater对象,这个 cloneInContext() 方法是一个抽象方法,由PhoneLayoutInflater实现:
# com.android.internal.policy.PhoneLayoutInflater
public PhoneLayoutInflater(Context context) {
super(context);
}
public LayoutInflater cloneInContext(Context newContext) {
return new PhoneLayoutInflater(this, newContext);
}
protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
super(original, newContext);
}
#android.view.LayoutInflater
protected LayoutInflater(LayoutInflater original, Context newContext) {
mContext = newContext;
mFactory = original.mFactory;
mFactory2 = original.mFactory2;
mPrivateFactory = original.mPrivateFactory;
setFilter(original.mFilter);
}
从上面的代码中也可以看到,调用 LayoutInflater的cloneInContext() 方法实际上就是创建了一个新的LayoutInflater对象,并且会把原来对象上的一些属性拷贝过来,如mFactory、mFactory2、mPrivateFactory、mFilter。这些factory 和 filter 就是为了从xml中加载布局来创建View对象时候用到的。
不过还有一点需要注意,PhoneLayoutInflater的一个构造方法中的Context是由ContextImpl的getOuterContext() 方法获取到的,那么这个mOuterContext是什么呢?
ContextImpl对象与Application、Activity、Service对象是一一绑定的。我们的ContextImpl 中的mOuterContext对象,这个在Activity中就是当前Activity对象,在Service中就是当前的Service对象。赋值时机是在ContextImpl对象创建后。ContextImpl的创建时机都是在ActivityThead中每次启动Activity或者Service或者一个新的Application的时候。
二、LayoutInflater怎么构建视图树的
- 从资源中找到对应的布局xml,然后创建一个XmlResourceParser对象用来解析便签。解析方式采用的是pull解析
# android.view.LayoutInflater
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
return inflate(resource, root, root != null);
}
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
+ Integer.toHexString(resource) + ")");
}
final XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
- 除了上面两个我们开发者经常使用的方法,还有一个3个参数的inflate方法。
- 第一个参数是XmlPullParser对象,我们把它当做一个解析标签的对象即可。
- 在这个inflate() 方法中会对所有的view标签(包括自定义View)、include、merge、ViewStub等进行处理
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
synchronized (mConstructorArgs) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext;
final AttributeSet attrs = Xml.asAttributeSet(parser);
Context lastContext = (Context) mConstructorArgs[0];
mConstructorArgs[0] = inflaterContext;
View result = root;
try {
// Look for the root node.
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty
}
...
final String name = parser.getName();
...
if (TAG_MERGE.equals(name)) {
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 //1!!!!!!!!********
final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) {
if (DEBUG) {
System.out.println("Creating params from root: " +
root);
}
// 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);
}
}
...
// *********2.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.
if (root == null || !attachToRoot) {
result = temp;
}
}
}
...
return result;
}
}
- 在该方法中有一个含有两个元素的数组 mConstructorArgs
- 这个就是在使用View的两个参数的构造方法时用于提供参数的。
- mConstructorArgs的第一个元素就是inflaterContext,实际上就是创建LayoutInflater对象的mContext。在一个Activity创建的LayoutInflater,mContext指向的就是这个Activity。
- 在注释1调用了 createViewFromTag() 方法。该方法又会调用其重载方法
- 在注释2处rInflateChildren遍历子view
2.1 createViewFromTag
# android.view.LayoutInflater
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) {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
// Apply a theme wrapper, if allowed and one is specified.
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();
}
// 1 开始创建View
try {
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);
}
if (view == null) {
final Object lastContext = mConstructorArgs[0];
mConstructorArgs[0] = context;
try {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
} finally {
mConstructorArgs[0] = lastContext;
}
}
return view;
...
}
public interface Factory {
public View onCreateView(String name, Context context, AttributeSet attrs);
}
public interface Factory2 extends Factory {
public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
}
-
会一次判断mFactory2、mFactory、mPrivateFactory是否会null,如果不为null的就按照优先级调用mFactory2、mFactory、mPrivateFactory的相关方法来创建View,只有前一个返回的View为null的时候,才会由后一个来创建
- mFactory2、mFactory、mPrivateFactory均有相关的set方法用于设置。
- 相信看到这里,就应该明白了我们之前讲的在clone一个原始的LayoutInflater的作用了,就是可以复用它的mFactory2、mFactory、mPrivateFactory,不需要再重新设置了
-
如果这几个创建的View都会null的话,就会调用LayoutInflater自身的方法来创建View
2.1.1 LayoutInflater的createView
- 首先通过View的名称来获取它的构造函数Constructor。
- 如果Constructor为null的话就会采用ClassLoader去加载对应的class。
- 需要注意的时候我们在xml填写的View的名称比如TextView,实际上是有全路径名的,即为:android.widget.TextView,类加载器加载必须要使用全路径名,因此对于TextView这样的Android系统自带的空间,需要加上全路径,因此可以在注释1处看到使用了prefix。
- 当Class加载成功的时候就会通过mConstructorSignature创建一个两个参数的构造器,对应的参数是 Context.class, AttributeSet.class, 值就是之前构造的值
- 之后就可以看到利用的反射的方式创建View对象。
# android.view.LayoutInflater
public final View createView(String name, String prefix, 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 {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, name);
if (constructor == null) {
// Class not found in the cache, see if it's real, and try to add it
//1
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
if (mFilter != null && clazz != null) {
boolean allowed = mFilter.onLoadClass(clazz);
if (!allowed) {
failNotAllowed(name, prefix, attrs);
}
}
constructor = clazz.getConstructor(mConstructorSignature);
constructor.setAccessible(true);
sConstructorMap.put(name, constructor);
} else {
// If we have a filter, apply it to cached constructor
if (mFilter != null) {
// Have we seen this name before?
Boolean allowedState = mFilterMap.get(name);
if (allowedState == null) {
// New class -- remember whether it is allowed
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
if (!allowed) {
failNotAllowed(name, prefix, attrs);
}
} else if (allowedState.equals(Boolean.FALSE)) {
failNotAllowed(name, prefix, attrs);
}
}
}
Object lastContext = mConstructorArgs[0];
if (mConstructorArgs[0] == null) {
// Fill in the context if not already within inflation.
mConstructorArgs[0] = mContext;
}
Object[] args = mConstructorArgs;
args[1] = attrs;
final View view = constructor.newInstance(args);
if (view instanceof ViewStub) {
// Use the same context when inflating ViewStub later.
final ViewStub viewStub = (ViewStub) view;
viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
}
mConstructorArgs[0] = lastContext;
return view;
...
}
- 最终,通过反射构造器传入View的两个参数的构造函数创建了View对象
- 第一个参数Context,传递的是LayoutInflater自身的mContext,对于Activity中的LayoutInflater,这个mContext就是Activity自身。
- 第二个是解析的xml属性
public View(Context context, @Nullable AttributeSet attrs)
因此在View中的Context实际上就是其所在的Activity对象。那么对于Fragment中的View也是这样的。
2.2 rInflateChildren
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)) {
pendingRequestFocus = true;
consumeChildElements(parser);
} else if (TAG_TAG.equals(name)) {
parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
}
parseInclude(parser, context, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
} else {
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();
}
}
内部递归rInflateChildren调用,实例化ViewTree
三、setContentView中的LayoutInflater什么时候创建
上面我们讲到的是开发者主动调用LayoutInflater的from方法来返回一个对象,但是我们知道一点是当在Activity中调用 setContentView(layoutRes) 方法的时候,会调用到PhoneWindow的setContentView(layoutRes) 方法,在该方法中通过LayoutInflater对象来创建View树了,那么这个LayoutInflater是什么时候创建的呢?
实际上,LayoutInflater的创建时机就是在Activity对象被创建出来之后。当Activity创建后,其attach方法就会被调用,在这个过程中Activity相关的对象或者属性就会被绑定,比如,PhoneWindow就是在这个时候被创建出来的。
# android.app.Activity
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) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
...
}
- 在PhoneWindow中有两个构造函数,一个有3个参数,一个有1个参数。3个参数的首先会调用1个参数的。在这个过程中调用了LayoutInflater的from 方法。来创建LayoutInflater对象。
//意:这个context对象就是Activity。
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
}
四、Fragment中的LayoutInflater
Fragment中有一个onCreateView() 方法,方法中有一个参数是LayoutInflater,这么LayoutInflater对象是从哪来的呢?
这个对象也是clone而来,而且是由Activity中的LayoutInflater clone而来。Fragment中的LayoutInflater与Activity中的LayoutInflater不是同一个对象,但既然是clone,Fragment中的LayoutInflater中把是Activity中的LayoutInflater中的mFactory、mFactory2、mPrivateFactory、mFilter变量全部赋值给自己相应的成员变量。注意:这是一个浅拷贝,也就是对象中的成员变量拷贝的是引用而不是实例。
Fragment是由FragmentManager来管理的,Fragment在创建阶段的生命周期方法是由FragmentManager的moveToState() 方法中回调的。代码很长,我们截取一些关键的信息,可以看到在这个方法中,Fragment的生命周期方法被回调。其中我们看到调用了Fragment的performCreateView() 方法,在参数中传递了LayoutInflater,而这个是通过调用的Fragment的 performGetLayoutInflater() 方法获得的
# android.app.FragmentManagerImpl
@SuppressWarnings("ReferenceEquality")
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
if (DEBUG && false) Log.v(TAG, "moveToState: " + f
+ " oldState=" + f.mState + " newState=" + newState
+ " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
// Fragments that are not currently added will sit in the onCreate() state.
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
// Allow the fragment to be created so that it can be saved later.
newState = Fragment.CREATED;
} else {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
}
// Defer start if requested; don't allow it to move to STARTED or higher
// if it's not already started.
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
if (f.mState <= newState) {
...
switch (f.mState) {
case Fragment.INITIALIZING:
...
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
f.onAttach(mHost.getContext());
...
case Fragment.CREATED:
// This is outside the if statement below on purpose; we want this to run
// even if we do a moveToState from CREATED => *, CREATED => CREATED, and
// * => CREATED as part of the case fallthrough above.
ensureInflatedFragmentView(f);
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
...
container = mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
String resName;
try {
resName = f.getResources().getResourceName(f.mContainerId);
...
}
f.mContainer = container;
f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
f.onViewCreated(f.mView, f.mSavedFragmentState);
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
// Only animate the view if it is visible. This is done after
// dispatchOnFragmentViewCreated in case visibility is changed
f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
&& f.mContainer != null;
}
}
f.performActivityCreated(f.mSavedFragmentState);
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
// fall through
...
}
}
}
...
}
- 来看一下Fragment的 performGetLayoutInflater() 方法,在该方法中又调用了其onGetLayoutInflater() 方法。
# android.support.v4.app.Fragment
LayoutInflater performGetLayoutInflater(Bundle savedInstanceState) {
LayoutInflater layoutInflater = onGetLayoutInflater(savedInstanceState);
mLayoutInflater = layoutInflater;
return mLayoutInflater;
}
public LayoutInflater getLayoutInflater(Bundle savedFragmentState) {
if (mHost == null) {
throw new IllegalStateException("onGetLayoutInflater() cannot be executed until the "
+ "Fragment is attached to the FragmentManager.");
}
LayoutInflater result = mHost.onGetLayoutInflater();
getChildFragmentManager(); // Init if needed; use raw implementation below.
LayoutInflaterCompat.setFactory2(result, mChildFragmentManager.getLayoutInflaterFactory());
return result;
}
4.1 onGetLayoutInflater
- 在Fragment的getLayoutInflater() 方法中,通过调用 mHost.onGetLayoutInflater()获取了一个LayoutInflater对象。mHost 就是FragmentHostCallback对象,来看一下它的onGetLayoutInflater() 方法:
# android.support.v4.app.FragmentHostCallback
public LayoutInflater onGetLayoutInflater() {
return (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
FragmentHostCallback的onGetLayoutInflater() 方法实际上就是调用了mContext的getSystemService方法,这个就跟我们前面分析的通过LayoutInflater的from方法是一个意思,mContext实际上就是Fragment所在的Activity。
Fragment中的LayoutInflater是由Activity中的LayoutInflater clone而来,它们不是同一个对象,不过Fragment中的LayoutInflater把Activity的LayoutInflater设置的一些factory copy过来,相当于它们使用的是同样的工厂。
4.2 LayoutInflater的setFactory2() 方法
在Fragmen的getLayoutInflater方法中调用了 LayoutInflaterCompat.setFactory2(result, mChildFragmentManager.getLayoutInflaterFactory()); ,其实就调用LayoutInflater的setFactory2() 方法
# android.view.LayoutInflater
public void setFactory2(Factory2 factory) {
if (mFactorySet) {
throw new IllegalStateException("A factory has already been set on this LayoutInflater");
}
if (factory == null) {
throw new NullPointerException("Given factory can not be null");
}
mFactorySet = true;
if (mFactory == null) {
mFactory = mFactory2 = factory;
} else {
mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2);
}
}
setFactory2方法很有意思,如果原来LayoutInflater上面的mFactory为null,就是把实际上mFactory、mFactory2均赋值为当前设置的factory。如果不为null创建了一个FactoryMerger对象赋值给mFactory、mFactory2。
假设我们之前在Activity中设置了mFactory2,那么当在Fragment中的LayoutInflater调用setFactory2方法的时候,mFactory 、mFactory2 均不为空,那么就会走到else里面,也就是说创建了一个FactoryMerger对象。FactoryMerger实际上实现了Factory2。
private static class FactoryMerger implements Factory2 {
private final Factory mF1, mF2;
private final Factory2 mF12, mF22;
FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
mF1 = f1;
mF2 = f2;
mF12 = f12;
mF22 = f22;
}
public View onCreateView(String name, Context context, AttributeSet attrs) {
View v = mF1.onCreateView(name, context, attrs);
if (v != null) return v;
return mF2.onCreateView(name, context, attrs);
}
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
View v = mF12 != null ? mF12.onCreateView(parent, name, context, attrs)
: mF1.onCreateView(name, context, attrs);
if (v != null) return v;
return mF22 != null ? mF22.onCreateView(parent, name, context, attrs)
: mF2.onCreateView(name, context, attrs);
}
}
- 当Fragment中的LayoutInflater中的Factory方法去执行的时候
- 实际上先执行的是mF12和mF1的onCreateView,我们知道在Fragment中设置的是mChildFragmentManager.getLayoutInflaterFactory(),mChildFragmentManager是FragmentManager,我们在Activity中通过getSupportFragmentManager获取也是FragmentManager对象。
- FragmentManager的实现类FragmentManagerImpl实现了Factory2接口,是用来解析fragment标签的。可以看到,如果标签不是fragment,实际上它还是会直接返回的
# android.support.v4.app.FragmentManager$FragmentManagerImpl
@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
if (!"fragment".equals(name)) {
return null;
}
…
return fragment.mView;
}
这样的设计下,Fragment会复用了Activity的Factory对象,只是在解析fragment标签的时候,采用用FragmentManagerImpl来解析