首页 > 学院 > 开发设计 > 正文

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

2019-11-09 17:35:31
字体:
来源:转载
供稿:网友

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

 Activity中的获取LayoutInflater对象及打印的对象地址LayoutInflater.from(this);   com.android.internal.policy.impl.PhoneLayoutInflater@41882b90LayoutInflater.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@4189f2f0LayoutInflater.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对象。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表