不同Context对象创建的LayoutInflater对象也不同

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

 Activity中的获取LayoutInflater对象及打印的对象地址
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


        另一Activity中的获取LayoutInflater对象及打印的对象地址


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

根据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()方法

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;
    }
该方法中调用了Context的getSystemService()方法,因为传的是this,即是Activity对象,Activity是也是Context对象,他们的继承关系为:Activity -> ContextThemeWrapper -> ContextWrapper -> Context。所以看Context的子类是否重写了getSystemService()方法,正好ContextThemeWrapper重写了,Activity也重写了,但和LayoutInflater没有关系,所以我们看ContextThemeWrapper中的getSystemService()方法

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);
    }
一开始的时候,mInflater肯定是为null,执行LayoutInflater.from(getBaseContext())方法,又回到了刚开始的LayoutInflater.from()方法,不一样的是这次上下文的对象是ContextImpl对象,为什么是ContextImpl,我们看getBaseContext()方法

public Context getBaseContext() {
        return mBase;
    }
该返回就只返回了mBase,我们看其是在哪里赋值的,是在ContextWrapper类的attachBaseContext方法中赋值的

protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
该方法又是在哪里调用的呢,是在Activity的attach方法中调用的

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) {
        attachBaseContext(context);
	......
    }
attach又是在哪里调用的呢,在ActivityThread中调用的

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);
		......
	    }
	......
}
而appContext又是createBaseContextForActivity(r, activity)方法返回的,

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;
    }
baseContext又是通过ContextImpl的createActivityContext()方法获取的

static 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);
    }
看到没,返回的对象是new ContextImpl出来的,所以之前的getBaseContext()获取的就是ContextImpl对象。所以不同对象的Context中的ContextImpl对象就不同,所以创建出来的LayoutInflater的对象可能就不同,往下看


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

@Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
SystemServiceRegistry的getSystemService方法

public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
我们在跟进getService()

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);
    }
它会先从cache中获取,如果没有就去创建createService,因为其实抽象的,所以看其实现类

registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});
到这里终于看到了LayoutInflater 对象 PhoneLayoutInflater,其实这还不是LayoutInflater.from(this)的最终对象,看ContextThemeWrapper 的mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);其实他在得到对象的时候又clone了一个

public LayoutInflater cloneInContext(Context newContext) {
        return new PhoneLayoutInflater(this, newContext);
    }
又new出了一个PhoneLayoutInflater对象,这才是LayoutInflater.from(this)返回的LayoutInflater对象
咱们再看一下LayoutInflater.from(getBaseContext())获取LayoutInflater方式,这个感觉在哪见过,没错就是在ContextThemeWrapper中的getSystemService方法中

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);
    }
其实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对象。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值