打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
不同Context对象创建的LayoutInflater对象也不同

创建LayoutInflater对象,根据所传的上下文对象不同,创建出来的LayoutInflater对象也不同,在不同Activity中创建的LayoutInflater对象也不同,先来看一下,

  1. Activity中的获取LayoutInflater对象及打印的对象地址
  2. LayoutInflater.from(this); com.android.internal.policy.impl.PhoneLayoutInflater@41882b90
  3. LayoutInflater.from(getApplication()); com.android.internal.policy.impl.PhoneLayoutInflater@418da098
  4. LayoutInflater.from(getBaseContext()); com.android.internal.policy.impl.PhoneLayoutInflater@41882b40
  5. getSystemService(Context.LAYOUT_INFLATER_SERVICE); com.android.internal.policy.impl.PhoneLayoutInflater@41882b90
  6. getApplication().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@418da098
  7. getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@41882b40
  8. getBaseContext(); android.app.ContextImpl@41882338
  9. getApplication().getBaseContext(); android.app.ContextImpl@41870230
  10. 另一Activity中的获取LayoutInflater对象及打印的对象地址
  11. LayoutInflater.from(this); com.android.internal.policy.impl.PhoneLayoutInflater@4189f2f0
  12. LayoutInflater.from(getApplication()); com.android.internal.policy.impl.PhoneLayoutInflater@418da098
  13. LayoutInflater.from(getBaseContext()); com.android.internal.policy.impl.PhoneLayoutInflater@4189f2a0
  14. getSystemService(Context.LAYOUT_INFLATER_SERVICE); com.android.internal.policy.impl.PhoneLayoutInflater@4189f2f0
  15. getApplication().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@418da098
  16. getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);com.android.internal.policy.impl.PhoneLayoutInflater@4189f2a0
  17. getBaseContext(); android.app.ContextImpl@4189ecd8
  18. getApplication().getBaseContext(); android.app.ContextImpl@41870230

根据LayoutInflate的form方法中的实现,其实LayoutInflater.from(this);LayoutInflater.from(getApplication());LayoutInflater.from(getBaseContext());和getSystemService(Context.LAYOUT_INFLATER_SERVICE);getApplication().getSystemService(Context.LAYOUT_INFLATER_SERVICE);getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);其实是一个意思,所以他们获取的对象都是一样的,那为什么不同上下文对象获取的LayoutInflater对象也不同呢,因为不同Context对象中的mBase(ContextImpl)对象不同,LayoutInflater就是在ContextImpl中创建的,所以创建的对象不同

下面咱来看一下LayoutInflater创建过程,咱们来跟踪一下代码,就拿LayoutInflater.from(this)来说,看LayoutInflater中的form()方法

  1. public static LayoutInflater from(Context context) {
  2. LayoutInflater LayoutInflater =
  3. (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  4. if (LayoutInflater == null) {
  5. throw new AssertionError('LayoutInflater not found.');
  6. }
  7. return LayoutInflater;
  8. }
该方法中调用了Context的getSystemService()方法,因为传的是this,即是Activity对象,Activity是也是Context对象,他们的继承关系为:Activity -> ContextThemeWrapper -> ContextWrapper -> Context。所以看Context的子类是否重写了getSystemService()方法,正好ContextThemeWrapper重写了,Activity也重写了,但和LayoutInflater没有关系,所以我们看ContextThemeWrapper中的getSystemService()方法
  1. public Object getSystemService(String name) {
  2. if (LAYOUT_INFLATER_SERVICE.equals(name)) {
  3. if (mInflater == null) {
  4. mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
  5. }
  6. return mInflater;
  7. }
  8. return getBaseContext().getSystemService(name);
  9. }
一开始的时候,mInflater肯定是为null,执行LayoutInflater.from(getBaseContext())方法,又回到了刚开始的LayoutInflater.from()方法,不一样的是这次上下文的对象是ContextImpl对象,为什么是ContextImpl,我们看getBaseContext()方法
  1. public Context getBaseContext() {
  2. return mBase;
  3. }
该返回就只返回了mBase,我们看其是在哪里赋值的,是在ContextWrapper类的attachBaseContext方法中赋值的
  1. protected void attachBaseContext(Context base) {
  2. if (mBase != null) {
  3. throw new IllegalStateException('Base context already set');
  4. }
  5. mBase = base;
  6. }
该方法又是在哪里调用的呢,是在Activity的attach方法中调用的
  1. final void attach(Context context, ActivityThread aThread,
  2. Instrumentation instr, IBinder token, int ident,
  3. Application application, Intent intent, ActivityInfo info,
  4. CharSequence title, Activity parent, String id,
  5. NonConfigurationInstances lastNonConfigurationInstances,
  6. Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
  7. attachBaseContext(context);
  8. ......
  9. }
attach又是在哪里调用的呢,在ActivityThread中调用的
  1. private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  2. ......
  3. if (activity != null) {
  4. Context appContext = createBaseContextForActivity(r, activity);
  5. CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
  6. Configuration config = new Configuration(mCompatConfiguration);
  7. if (DEBUG_CONFIGURATION) Slog.v(TAG, 'Launching activity '
  8. + r.activityInfo.name + ' with config ' + config);
  9. activity.attach(appContext, this, getInstrumentation(), r.token,
  10. r.ident, app, r.intent, r.activityInfo, title, r.parent,
  11. r.embeddedID, r.lastNonConfigurationInstances, config,
  12. r.referrer, r.voiceInteractor);
  13. ......
  14. }
  15. ......
  16. }
而appContext又是createBaseContextForActivity(r, activity)方法返回的,
  1. private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
  2.         ......
  3.         ContextImpl appContext = ContextImpl.createActivityContext(
  4.                 this, r.packageInfo, displayId, r.overrideConfig);
  5.         appContext.setOuterContext(activity);
  6.         Context baseContext = appContext;
  7.         final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
  8.         String pkgName = SystemProperties.get('debug.second-display.pkg');
  9.         if (pkgName != null && !pkgName.isEmpty()
  10.                 && r.packageInfo.mPackageName.contains(pkgName)) {
  11.             for (int id : dm.getDisplayIds()) {
  12.                 if (id != Display.DEFAULT_DISPLAY) {
  13.                     Display display =
  14.                             dm.getCompatibleDisplay(id, appContext.getDisplayAdjustments(id));
  15.                     baseContext = appContext.createDisplayContext(display);
  16.                     break;
  17.                 }
  18.             }
  19.         }
  20.         return baseContext;
  21.     }
baseContext又是通过ContextImpl的createActivityContext()方法获取的
  1. static ContextImpl createActivityContext(ActivityThread mainThread,
  2. LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
  3. if (packageInfo == null) throw new IllegalArgumentException('packageInfo');
  4. return new ContextImpl(null, mainThread, packageInfo, null, null, false,
  5. null, overrideConfiguration, displayId);
  6. }
看到没,返回的对象是new ContextImpl出来的,所以之前的getBaseContext()获取的就是ContextImpl对象。所以不同对象的Context中的ContextImpl对象就不同,所以创建出来的LayoutInflater的对象可能就不同,往下看


所以我们再看LayoutInflater.from()中的context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)语句,这个context就是ContextImpl对象,看其方法

  1. @Override
  2. public Object getSystemService(String name) {
  3. return SystemServiceRegistry.getSystemService(this, name);
  4. }
SystemServiceRegistry的getSystemService方法
  1. public static Object getSystemService(ContextImpl ctx, String name) {
  2. ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
  3. return fetcher != null ? fetcher.getService(ctx) : null;
  4. }
我们在跟进getService()
  1. static abstract interface ServiceFetcher<T> {
  2. T getService(ContextImpl ctx);
  3. }
  4. static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
  5. private final int mCacheIndex;
  6. public CachedServiceFetcher() {
  7. mCacheIndex = sServiceCacheSize++;
  8. }
  9. @Override
  10. @SuppressWarnings('unchecked')
  11. public final T getService(ContextImpl ctx) {
  12. final Object[] cache = ctx.mServiceCache;
  13. synchronized (cache) {
  14. // Fetch or create the service.
  15. Object service = cache[mCacheIndex];
  16. if (service == null) {
  17. service = createService(ctx);
  18. cache[mCacheIndex] = service;
  19. }
  20. return (T)service;
  21. }
  22. }
  23. public abstract T createService(ContextImpl ctx);
  24. }
它会先从cache中获取,如果没有就去创建createService,因为其实抽象的,所以看其实现类
  1. registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
  2. new CachedServiceFetcher<LayoutInflater>() {
  3. @Override
  4. public LayoutInflater createService(ContextImpl ctx) {
  5. return new PhoneLayoutInflater(ctx.getOuterContext());
  6. }});
到这里终于看到了LayoutInflater 对象 PhoneLayoutInflater,其实这还不是LayoutInflater.from(this)的最终对象,看ContextThemeWrapper 的mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);其实他在得到对象的时候又clone了一个
  1. public LayoutInflater cloneInContext(Context newContext) {
  2. return new PhoneLayoutInflater(this, newContext);
  3. }
又new出了一个PhoneLayoutInflater对象,这才是LayoutInflater.from(this)返回的LayoutInflater对象
咱们再看一下LayoutInflater.from(getBaseContext())获取LayoutInflater方式,这个感觉在哪见过,没错就是在ContextThemeWrapper中的getSystemService方法中
  1. public Object getSystemService(String name) {
  2. if (LAYOUT_INFLATER_SERVICE.equals(name)) {
  3. if (mInflater == null) {
  4. mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
  5. }
  6. return mInflater;
  7. }
  8. return getBaseContext().getSystemService(name);
  9. }
其实LayoutInflater.from(getBaseContext())获取LayoutInflater对象就是LayoutInflater.from(this)获取的LayoutInflater对象在其没有执行cloneInContext(this)方法时创建的PhoneLayoutInflater对象。再一个就是LayoutInflater.from(getApplication());获取LayoutInflater对象方式,因为getApplication()获取的是全局的Application对象,其内部的ContextImpl对象也不同,所以得到的LayoutInflater对象和之前两个也不同,还有就是不管在哪个Activity中getApplication()获取的Context都是同一个对象,所以LayoutInflater.from(getApplication());获取的LayoutInflater对象都是同一个。

好了,这就是为什么不同的Context对象获取LayoutInflater是不同的对象。从刚开始的getBaseContext();   android.app.ContextImpl@41882338就可以看出getBaseContext()获取的是ContextImpl对象,和getApplication().getBaseContext();   android.app.ContextImpl@41870230获取的都是同一个ContextImpl对象。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Android 2.3 SD卡挂载流程浅析(六)
Alarm机制与Binder交互
Android LayoutInflater详解
getSystemService() in Android
深入浅出
Android - LayoutInflater
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服