明明白白学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; }
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); }
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();大家感兴趣的话可以自己尝试着分析一下
- 明明白白学android系列一(Context剖析)
- android Context深度剖析
- DotNet剖析系列(一)
- 明明白白c++ 解读effective c++系列一(条目1-5)
- 【MVC框架系列】(一)——Struts,让我把你看得明明白白
- 明明白白学C#
- 【42】android Context深度剖析
- 明明白白学编程(C语言)第一讲!!!
- 明明白白学通C语言(二维码版)
- 明明白白学通C语言(二维码版)
- Android广播注册机制剖析【android广播系列一】
- Android中Context源码分析(一)
- Android context的理解(一)
- Android深入理解Context(一)Context关联类和Application Context创建过程
- 学习笔记--《Android内核剖析》Context
- android内核剖析 Context理解读书笔记
- Android系列教程之Context
- 一步一步学Android(一)
- jsp实验2.mysql数据库操作
- 最长公共字符串 基础DP
- 字符串逆序(重新申请空间和不用)
- mysql主从同步 binlog-do-db replicate-do-db
- 第三十五讲项目二 反弹的皮球
- 明明白白学android系列一(Context剖析)
- 前端学习笔记之js中apply()和call()方法详解
- linux下压缩与解压缩-tar和zip
- 【CSS】1.概述
- 数据结构-二叉树(递归前序、中序、后序遍历;栈实现中序变量;二叉树镜像)
- net-snmp debug
- 静态链表 C实现
- SignalTap II的参考时钟配置
- USB TYPE C接口拆解及定义、USB3.1标准说明