Create LayoutInflater objects. According to the context objects that are uploaded, the LayoutInflater objects are created differently. The LayoutInflater objects created in different activities are also different. Let's take a look at them first.
Activity Acquisition in LayoutInflater Object and Printed Object Address LayoutInflater.from(this); com.android.internal.policy.impl.PhoneLayoutInflater@41882b90 LayoutInflater.from(getApplication()); com.android.internal.policy.impl.PhoneLayoutInflater@418da098 LayoutInflater.from(getBaseContext()); com.android.internal.policy.impl.PhoneLayoutInflater@41882b40 getSystemService(Context.LAYOUT_INFLATER_SERVICE); com.android.internal.policy.impl.PhoneLayoutInflater@41882b90 getApplication().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@418da098 getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@41882b40 getBaseContext(); android.app.ContextImpl@41882338 getApplication().getBaseContext(); android.app.ContextImpl@41870230 //Getting the LayoutInflater object and the printed object address in another Activity LayoutInflater.from(this); com.android.internal.policy.impl.PhoneLayoutInflater@4189f2f0 LayoutInflater.from(getApplication()); com.android.internal.policy.impl.PhoneLayoutInflater@418da098 LayoutInflater.from(getBaseContext()); com.android.internal.policy.impl.PhoneLayoutInflater@4189f2a0 getSystemService(Context.LAYOUT_INFLATER_SERVICE); com.android.internal.policy.impl.PhoneLayoutInflater@4189f2f0 getApplication().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@418da098 getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@4189f2a0 getBaseContext(); android.app.ContextImpl@4189ecd8 getApplication().getBaseContext(); android.app.ContextImpl@41870230
According to the implementation of the form method of LayoutInflate, in fact, LayoutInflater. from (this); LayoutInflater. from (getApplication (); LayoutInflater. from (getBaseContext (); and getSystemService (Context. LAYOUT_INFLATER_SERVICE); getSystem Application (Context. LAYOUT_INFLATER_SERVICE); getContext (); (Context. So they get the same object, so why don't they get different LayoutInflater objects from different context objects, because mBase (ContextImpl) objects in different context objects are different, LayoutInflater is created in ContextImpl, so the objects created are different.
Let's take a look at the LayoutInflater creation process. Let's track the code. Take LayoutInflater.from(this) for example, look at the form() method in LayoutInflater.
In this method, the getSystemService() method of Context is invoked, because this is passed, that is, the Activity object, and the Activity is also the Context object. Their inheritance relationship is: Activity - > ContextThemeWrapper - > ContextWrapper - > Context. So to see if the subclass of Context overrides the getSystemService() method, it happens that ContextThemeWrapper overrides and Activity overrides, but it has nothing to do with LayoutInflater, so let's look at the getSystemService() method in ContextThemeWrapper.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; }
At the beginning, mInflater must be for null, executing the LayoutInflater.from(getBaseContext()) method, and returning to the original LayoutInflater.from() method. The difference is that the object of this context is the ContextImpl object, why is it the ContextImpl? Let's look at the getBaseContext() method.public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); } return mInflater; } return getBaseContext().getSystemService(name); }
This return only returns mBase. Let's see where it's assigned. It's assigned in the attachBaseContext method of the ContextWrapper class.public Context getBaseContext() { return mBase; }
Where is this method called? It's called in Activity's attach method.protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; }
Where is attach called, in ActivityThreadfinal 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) { attachBaseContext(context); ...... }
appContext is returned by the createBaseContextForActivity(r, activity) method.private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ...... if (activity != null) { Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); 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); ...... } ...... }
The baseContext is also obtained by the createActivityContext() method of ContextImpl.private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) { ...... ContextImpl appContext = ContextImpl.createActivityContext( this, r.packageInfo, displayId, r.overrideConfig); appContext.setOuterContext(activity); Context baseContext = appContext; final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); String pkgName = SystemProperties.get("debug.second-display.pkg"); if (pkgName != null && !pkgName.isEmpty() && r.packageInfo.mPackageName.contains(pkgName)) { for (int id : dm.getDisplayIds()) { if (id != Display.DEFAULT_DISPLAY) { Display display = dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id)); baseContext = appContext.createDisplayContext(display); break; } } } return baseContext; }
See, the returned object is new ContextImpl, so the previous getBaseContext() gets the ContextImpl object. So the ContextImpl objects in the Context of different objects are different, so the LayoutInflate objects created may be different. Look downstatic ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); return new ContextImpl(null, mainThread, packageInfo, null, null, false, null, overrideConfiguration, displayId); }
So let's look at the context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) statement in LayoutInflater.from(), which is the ContextImpl object, and see how it works.
GetSystem Service Method of System Service Registry@Override public Object getSystemService(String name) { return SystemServiceRegistry.getSystemService(this, name); }
We are following up getService()public static Object getSystemService(ContextImpl ctx, String name) { ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name); return fetcher != null ? fetcher.getService(ctx) : null; }
It gets it from cache first, and if it doesn't, it creates createService, because it's abstract, so look at its implementation class.static abstract interface ServiceFetcher<T> { T getService(ContextImpl ctx); } static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> { private final int mCacheIndex; public CachedServiceFetcher() { mCacheIndex = sServiceCacheSize++; } @Override @SuppressWarnings("unchecked") public final T getService(ContextImpl ctx) { final Object[] cache = ctx.mServiceCache; synchronized (cache) { // Fetch or create the service. Object service = cache[mCacheIndex]; if (service == null) { service = createService(ctx); cache[mCacheIndex] = service; } return (T)service; } } public abstract T createService(ContextImpl ctx); }
At last, I saw the LayoutInflater object PhoneLayoutInflater, which is not the final object of LayoutInflater.from(this). Look at the mInflater = LayoutInflater. From (getBaseContext (). CloneInContext (this); in fact, when he got the object, he clone d another one.registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class, new CachedServiceFetcher<LayoutInflater>() { @Override public LayoutInflater createService(ContextImpl ctx) { return new PhoneLayoutInflater(ctx.getOuterContext()); }});
Another PhoneLayoutInflater object came out, which is the LayoutInflate object returned by LayoutInflater.from(this)public LayoutInflater cloneInContext(Context newContext) { return new PhoneLayoutInflater(this, newContext); }
Let's take a look at the LayoutInflater.from(getBaseContext()) to get the LayoutInflater way. Where have we seen this feeling? That's right in the getSystemService method in ContextThemeWrapper
In fact, the LayoutInflater.from(getBaseContext()) acquisition of the LayoutInflate object is the LayoutInflater.from(this) acquisition of the LayoutInflate object created by the LayoutInflate object when it did not execute the cloneInContext(this) method. Another is LayoutInflater. from (getApplication(); the way to get LayoutInflate objects, because getApplication() gets global Application objects, and its internal ContextImpl objects are different, so the resulting LayoutInflate objects are different from the previous two, and that is, regardless of which Activity getApplication() obtains the same object. So LayoutInflater.from(getApplication()); the acquired LayoutInflate object is the same.public Object getSystemService(String name) { if (LAYOUT_INFLATER_SERVICE.equals(name)) { if (mInflater == null) { mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this); } return mInflater; } return getBaseContext().getSystemService(name); }
Okay, that's why different Context objects get LayoutInflater from different objects. From the initial getBaseContext(); android.app.ContextImpl@41882338, you can see that getBaseContext() takes the ContextImpl object, and getApplication().getBaseContext(); android.app.ContextImpl@41870230 takes the same ContextImpl object.