明明白白学android系列一(Context剖析)

来源:互联网 发布:django ajax json 编辑:程序博客网 时间:2024/05/18 13:29

Context在安卓开发中应用是非常频繁的,那么问题来了:为什么叫context

Context中文翻译为上下文,起着承上启下的作用,我们先来看几个大家都熟悉的context用法 

        getResources().getDrawable(R.drawable.ic_launcher);getResources().getAssets();getFilesDir();getCacheDir();getApplicationInfo();getPackageName();getSharedPreferences("", 0);getSystemService(Context.WINDOW_SERVICE);startActivity(new Intent());startService(new Intent());sendBroadcast(new Intent());


可以看出获取res目录下或者assets目录下的资源时我们需要使用context获取,获取manifest描述的应用信息时需要使用context,启动一个activity、一个service,发送一个广播时我们需要使用context,那么这个上下文也就很好解释了,context向上连接着应用程序,向下连接着应用资源(也就是res和assets目录下的所有内容),系统服务(例如窗口管理、通知管理、闹钟管理服务),其他需要和系统服务交互的操作(例如启动一个activity、service需要和ActivityManagerService交互),所以Context是应用程序和 程序中的资源、android系统之间的沟通的桥梁,可以说这个类极大的方便了我们的编码工作,不需要我们直接和系统对接,而是在其内部将这些进行封装,我们只需要调用对应的方法即可。


既然这个类有着这么大的本事,那么我们赶紧来看看这个神一般存在的类吧,话不多说,这个类的具体实现类有很多,像Activity、Application,但是真正的实现者是ContextImpl,Activity和Application虽然也实现了Context类中的抽象方法,但是他们都是通过内部的mBase持有着对一个ContextImpl实例的引用,比如Activity  getResource方法的实现,在Activity中没有实现这个方法,而是在其父类ContextThemeWrapper中实现的

    @Override    public Resources getResources() {        if (mResources != null) {            return mResources;        }        if (mOverrideConfiguration == null) {            mResources = super.getResources();            return mResources;        } else {            Context resc = createConfigurationContext(mOverrideConfiguration);            mResources = resc.getResources();            return mResources;        }    }

这里又调用了ContextThemeWrapper得父类ContextWrapper

    

    @Override    public Resources getResources()    {        return mBase.getResources();    }

那么mBase又是怎么来的

    protected void attachBaseContext(Context base) {        if (mBase != null) {            throw new IllegalStateException("Base context already set");        }        mBase = base;    }


attachBaseContext是在Activity中的attch方法中调用的,attach方法是在ActivityThread中创建Activity实例对象后调用的,看下面的代码
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.voiceInteractor);

通过attach方法将appContext传递到Activity中,并调用attachBaseContext方法,将appContext赋值给mBase,appContext又是通过createBaseContextForActivity来创建


ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);        appContext.setOuterContext(activity);        Context baseContext = appContext;        final DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();        try {            IActivityContainer container =                    ActivityManagerNative.getDefault().getEnclosingActivityContainer(r.token);            final int displayId =                    container == null ? Display.DEFAULT_DISPLAY : container.getDisplayId();            if (displayId > Display.DEFAULT_DISPLAY) {                Display display = dm.getRealDisplay(displayId, r.token);                baseContext = appContext.createDisplayContext(display);            }        } catch (RemoteException e) {        }

通过上面的代码可以看出,appContext实际上就是ContextImpl的一个实例对象


这也就说明了虽然安卓中的context有几个实现类,但真正的实现类是ContextImpl,接下来我们继续分析ContextImpl是如何实现context中的抽象方法的

getSystemService

    @Override    public Object getSystemService(String name) {        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);        return fetcher == null ? null : fetcher.getService(this);    }


当调用getSystemService时,会从静态map集合中获取到ServiceFetcher

static {        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {                public Object getService(ContextImpl ctx) {                    return AccessibilityManager.getInstance(ctx);                }});        registerService(CAPTIONING_SERVICE, new ServiceFetcher() {                public Object getService(ContextImpl ctx) {                    return new CaptioningManager(ctx);                }});        registerService(ACCOUNT_SERVICE, new ServiceFetcher() {                public Object createService(ContextImpl ctx) {                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);                    IAccountManager service = IAccountManager.Stub.asInterface(b);                    return new AccountManager(ctx, service);                }});        registerService(ACTIVITY_SERVICE, new ServiceFetcher() {                public Object createService(ContextImpl ctx) {                    return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());                }});        registerService(ALARM_SERVICE, new ServiceFetcher() {                public Object createService(ContextImpl ctx) {                    IBinder b = ServiceManager.getService(ALARM_SERVICE);                    IAlarmManager service = IAlarmManager.Stub.asInterface(b);                    return new AlarmManager(service, ctx);                }});


服务注册函数

    private static void registerService(String serviceName, ServiceFetcher fetcher) {        if (!(fetcher instanceof StaticServiceFetcher)) {            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;        }        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);    }

在类的加载解析初始化阶段会把安卓系统提供给客户端使用的各种服务存入这个map集合中,客户端即可通过Context获取到ContextImpl的引用,然后获取到系统服务

getResource

    @Override    public Resources getResources() {        return mResources;    }
直接返回了实例mResource,看mResource是怎么赋值的

private ContextImpl(ContextImpl container, ActivityThread mainThread,            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,            Display display, Configuration overrideConfiguration) {        mOuterContext = this;        mMainThread = mainThread;        mActivityToken = activityToken;        mRestricted = restricted;        if (user == null) {            user = Process.myUserHandle();        }        mUser = user;        mPackageInfo = packageInfo;        mResourcesManager = ResourcesManager.getInstance();        mDisplay = display;        mOverrideConfiguration = overrideConfiguration;        final int displayId = getDisplayId();        CompatibilityInfo compatInfo = null;        if (container != null) {            compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();        }        if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) {            compatInfo = packageInfo.getCompatibilityInfo();        }        mDisplayAdjustments.setCompatibilityInfo(compatInfo);        mDisplayAdjustments.setActivityToken(activityToken);        Resources resources = packageInfo.getResources(mainThread);        if (resources != null) {            if (activityToken != null                    || displayId != Display.DEFAULT_DISPLAY                    || overrideConfiguration != null                    || (compatInfo != null && compatInfo.applicationScale                            != resources.getCompatibilityInfo().applicationScale)) {                resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),                        packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),                        packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,                        overrideConfiguration, compatInfo, activityToken);            }        }        mResources = resources;        ...    }

这段代码中,resource赋值有两个地方,

第一个地方是

Resources resources = packageInfo.getResources(mainThread);

第二个地方是

 resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                        packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                        packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
                        overrideConfiguration, compatInfo, activityToken);

第一个地方最终也会调用第二个地方这个函数,区别是会传递不同的参数,会参与到资源Resource对象的生成


    public Resources getTopLevelResources(String resDir, String[] splitResDirs,            String[] overlayDirs, String[] libDirs, int displayId,            Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {        final float scale = compatInfo.applicationScale;        ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, token);        Resources r;        synchronized (this) {            // Resources is app scale dependent.            if (false) {                Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);            }            WeakReference<Resources> wr = mActiveResources.get(key);            r = wr != null ? wr.get() : null;            //if (r != null) Slog.i(TAG, "isUpToDate " + resDir + ": " + r.getAssets().isUpToDate());            if (r != null && r.getAssets().isUpToDate()) {                if (false) {                    Slog.w(TAG, "Returning cached resources " + r + " " + resDir                            + ": appScale=" + r.getCompatibilityInfo().applicationScale);                }                return r;            }        }        //if (r != null) {        //    Slog.w(TAG, "Throwing away out-of-date resources!!!! "        //            + r + " " + resDir);        //}        AssetManager assets = new AssetManager();        // resDir can be null if the 'android' package is creating a new Resources object.        // This is fine, since each AssetManager automatically loads the 'android' package        // already.        if (resDir != null) {            if (assets.addAssetPath(resDir) == 0) {                return null;            }        }        if (splitResDirs != null) {            for (String splitResDir : splitResDirs) {                if (assets.addAssetPath(splitResDir) == 0) {                    return null;                }            }        }        if (overlayDirs != null) {            for (String idmapPath : overlayDirs) {                assets.addOverlayPath(idmapPath);            }        }        if (libDirs != null) {            for (String libDir : libDirs) {                if (assets.addAssetPath(libDir) == 0) {                    Slog.w(TAG, "Asset path '" + libDir +                            "' does not exist or contains no resources.");                }            }        }        //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);        DisplayMetrics dm = getDisplayMetricsLocked(displayId);        Configuration config;        boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);        final boolean hasOverrideConfig = key.hasOverrideConfiguration();        if (!isDefaultDisplay || hasOverrideConfig) {            config = new Configuration(getConfiguration());            if (!isDefaultDisplay) {                applyNonDefaultDisplayMetricsToConfigurationLocked(dm, config);            }            if (hasOverrideConfig) {                config.updateFrom(key.mOverrideConfiguration);            }        } else {            config = getConfiguration();        }        r = new Resources(assets, dm, config, compatInfo, token);        if (false) {            Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "                    + r.getConfiguration() + " appScale="                    + r.getCompatibilityInfo().applicationScale);        }        synchronized (this) {            WeakReference<Resources> wr = mActiveResources.get(key);            Resources existing = wr != null ? wr.get() : null;            if (existing != null && existing.getAssets().isUpToDate()) {                // Someone else already created the resources while we were                // unlocked; go ahead and use theirs.                r.getAssets().close();                return existing;            }            // XXX need to remove entries when weak references go away            mActiveResources.put(key, new WeakReference<Resources>(r));            return r;        }    }

r = new Resources(assets, dm, config, compatInfo, token);生成了Resource对象,最后以若引用的方式缓存到mActiveResources中


这样就生成了Resource对象,我们便可以通过这个对象获取到所有的程序资源


其他的函数例如getApplicationInfo();getFilesDir();大家感兴趣的话可以自己尝试着分析一下









0 0
原创粉丝点击