Application context activity和Activity context activity的区别

android Context上下文详细了解以及使用 - 学无止境 - ITeye技术网站
博客分类:
1.Context基本概念
Context是什么
1) Context是一个抽象类,其通用实现在ContextImpl类中。
2) Context:是一个访问Application环境全局信息的接口,通过它可以访问application的资源和相关的类,其主要功能如下:
A.启动Activity
B.启动和停止Service
C.发送广播消息(Intent)
D.注册广播消息(Intent)接收者
可以访问APK中各种资源(如Resources和AssetManager等)
可以访问Package的相关信息
APK的各种权限管理
从以上分析可以看出,Context就是一个对APK包无所不知的大管家,大家需要什么,直接问它就可以了。
2.Context与View的关系
View与Context(或Activity)的关系类似于明星与经纪人的关系,所以创建View时,必须明确指定其Context(即经纪人或大管家),否则View就成不了明星。
Context家族关系:
Context类内容
public abstract class Context {
// 获取应用程序包的AssetManager实例
public abstract AssetManager getAssets();
// 获取应用程序包的Resources实例
public abstract Resources getResources();
// 获取PackageManager实例,以查看全局package信息
public abstract PackageManager getPackageManager();
// 获取应用程序包的ContentResolver实例
public abstract ContentResolver getContentResolver();
// 它返回当前进程的主线程的Looper,此线程分发调用给应用组件(activities, services等)
public abstract Looper getMainLooper();
// 返回当前进程的单实例全局Application对象的Context
public abstract Context getApplicationContext();
// 从string表中获取本地化的、格式化的字符序列
public final CharSequence getText(int resId) {
return getResources().getText(resId);
// 从string表中获取本地化的字符串
public final String getString(int resId) {
return getResources().getString(resId);
public final String getString(int resId, Object... formatArgs) {
return getResources().getString(resId, formatArgs);
// 返回一个可用于获取包中类信息的class loader
public abstract ClassLoader getClassLoader();
// 返回应用程序包名
public abstract String getPackageName();
// 返回应用程序信息
public abstract ApplicationInfo getApplicationInfo();
// 根据文件名获取SharedPreferences
public abstract SharedPreferences getSharedPreferences(String name, int mode);
// 其根目录为: Environment.getExternalStorageDirectory()
* @param type The type of files directory to return. May be null for the
* root of the files directory or one of the following Environment constants
* for a subdirectory: {@link android.os.Environment#DIRECTORY_MUSIC},
* {@link android.os.Environment#DIRECTORY_PODCASTS}, {@link
* android.os.Environment#DIRECTORY_RINGTONES}, {@link
* android.os.Environment#DIRECTORY_ALARMS}, {@link
* android.os.Environment#DIRECTORY_NOTIFICATIONS}, {@link
* android.os.Environment#DIRECTORY_PICTURES}, or {@link
* android.os.Environment#DIRECTORY_MOVIES}.
public abstract File getExternalFilesDir(String type);
// 返回应用程序obb文件路径
public abstract File getObbDir();
// 启动一个新的activity
public abstract void startActivity(Intent intent);
// 启动一个新的activity
public void startActivityAsUser(Intent intent, UserHandle user) {
throw new RuntimeException(
"Not implemented. Must override in a subclass.");
// 启动一个新的activity
// intent: 将被启动的activity的描述信息
// options: 描述activity将如何被启动
public abstract void startActivity(Intent intent, Bundle options);
// 启动多个新的activity
public abstract void startActivities(Intent[] intents);
// 启动多个新的activity
public abstract void startActivities(Intent[] intents, Bundle options);
// 广播一个intent给所有感兴趣的接收者,异步机制
public abstract void sendBroadcast(Intent intent);
// 广播一个intent给所有感兴趣的接收者,异步机制
public abstract void sendBroadcast(Intent intent, String receiverPermission);
public abstract void sendOrderedBroadcast(Intent intent,
String receiverPermission);
public abstract void sendOrderedBroadcast(Intent intent,
String receiverPermission, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras);
public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);
public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission);
// 注册一个BroadcastReceiver,且它将在主activity线程中运行
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter);
public abstract Intent registerReceiver(BroadcastReceiver receiver,
IntentFilter filter, String broadcastPermission, Handler scheduler);
public abstract void unregisterReceiver(BroadcastReceiver receiver);
// 请求启动一个application service
public abstract ComponentName startService(Intent service);
// 请求停止一个application service
public abstract boolean stopService(Intent service);
// 连接一个应用服务,它定义了application和service间的依赖关系
public abstract boolean bindService(Intent service, ServiceConnection conn,
int flags);
// 断开一个应用服务,当服务重新开始时,将不再接收到调用,
// 且服务允许随时停止
public abstract void unbindService(ServiceConnection conn);
// 返回系统级service句柄
* @see #WINDOW_SERVICE
* @see android.view.WindowManager
* @see #LAYOUT_INFLATER_SERVICE
* @see android.view.LayoutInflater
* @see #ACTIVITY_SERVICE
* @see android.app.ActivityManager
* @see #POWER_SERVICE
* @see android.os.PowerManager
* @see #ALARM_SERVICE
* @see android.app.AlarmManager
* @see #NOTIFICATION_SERVICE
* @see android.app.NotificationManager
* @see #KEYGUARD_SERVICE
* @see android.app.KeyguardManager
* @see #LOCATION_SERVICE
* @see android.location.LocationManager
* @see #SEARCH_SERVICE
* @see android.app.SearchManager
* @see #SENSOR_SERVICE
* @see android.hardware.SensorManager
* @see #STORAGE_SERVICE
* @see android.os.storage.StorageManager
* @see #VIBRATOR_SERVICE
* @see android.os.Vibrator
* @see #CONNECTIVITY_SERVICE
* @see android.net.ConnectivityManager
* @see #WIFI_SERVICE
* @see android.net.wifi.WifiManager
* @see #AUDIO_SERVICE
* @see android.media.AudioManager
* @see #MEDIA_ROUTER_SERVICE
* @see android.media.MediaRouter
* @see #TELEPHONY_SERVICE
* @see android.telephony.TelephonyManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
* @see #UI_MODE_SERVICE
* @see android.app.UiModeManager
* @see #DOWNLOAD_SERVICE
* @see android.app.DownloadManager
public abstract Object getSystemService(String name);
public abstract int checkPermission(String permission, int pid, int uid);
// 返回一个新的与application name对应的Context对象
public abstract Context createPackageContext(String packageName, int flags)
throws PackageManager.NameNotFoundE
// 返回基于当前Context对象的新对象,其资源与display相匹配
public abstract Context createDisplayContext(Display display);
3.何时创建Context
应用程序在以下几种情况下创建Context实例:
1) 创建Application对象时,而且整个App共一个Application对象
2) 创建Service对象时
3) 创建Activity对象时
因此应用程序App共有的Context数目公式为:
总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)
通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的所有ContextImpl实例,都对应同一个packageInfo对象。
浏览: 73091 次
来自: 深圳Context在android中的作用不言而喻,当我们访问当前应用的资源,启动一个新的activity的时候都需要提供Context,而这个Context到底是什么呢,这个问题好像很好回答又好像难以说清楚。从字面意思,Context的意思是&上下文&,或者也可以叫做环境、场景等,尽管如此,还是有点抽象。从类的继承来说,Context作为一个抽象的基类,它的实现子类有三种:Application、Activity和Service(估计这么说,暂时不管ContextWrapper等类),那么这三种有没有区别呢?为什么通过任意的Context访问资源都得到的是同一套资源呢?getApplication和getApplicationContext有什么区别呢?应用中到底有多少个Context呢?本文将围绕这些问题一一展开,所用源码版本为Android4.4。
什么是Context
Context是一个抽象基类,我们通过它访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),当然,通过Context能得到的不仅仅只有上述这些内容。对Context的理解可以来说:Context提供了一个应用的运行环境,在Context的大环境里,应用才可以访问资源,才能完成和其他组件、服务的交互,Context定义了一套基本的功能接口,我们可以理解为一套规范,而Activity和Service是实现这套规范的子类,这么说也许并不准确,因为这套规范实际是被ContextImpl类统一实现的,Activity和Service只是继承并有选择性地重写了某些规范的实现。
Application、Activity和Service作为Context的区别
首先,它们都间接继承了Context,这是它们的相同点。
不同点,可以从几个方面来说:首先看它们的继承关系
Activity的继承关系
Service和Application的继承关系
通过对比可以清晰地发现,Service和Application的类继承关系比较像,而Activity还多了一层继承ContextThemeWrapper,这是因为Activity有主题的概念,而Service是没有界面的服务,Application更是一个抽象的东西,它也是通过Activity类呈现的。
下面来看一下三者在Context方面的区别
上文已经指出,Context的真正实现都在ContextImpl中,也就是说Context的大部分方法调用都会转到ContextImpl中,而三者的创建均在ActivityThread中完成,我之前写过一篇文章,在文中我指出Activity启动的核心过程是在ActivityThread中完成的,这里要说明的是,Application和Service的创建也是在ActivityThread中完成的。下面我们看下三者在创建时是怎么和ContextImpl相关联的。
Activity对象中ContextImpl的创建
代码为ActivityThread中的performLaunchActivity方法&
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);&&
&&&&if&(customIntent&!=&null)&{&&
&&&&&&&&activity.mIntent&=&customI&&
可以看出,Activity在创建的时候会new一个ContextImpl对象并在attach方法中关联它,需要注意的是,创建Activity使用的数据结构是ActivityClientRecord。
Application对象中ContextImpl的创建
代码在ActivityThread中的handleBindApplication方法中,此方法内部调用了makeApplication方法&
public&Application&makeApplication(boolean&forceDefaultAppClass,&&
&&&&&&&&Instrumentation&instrumentation)&{&&
&&&&if&(mApplication&!=&null)&{&&
&&&&&&&&return&mA&&
&&&&Application&app&=&&&
&&&&String&appClass&=&mApplicationInfo.classN&&
&&&&if&(forceDefaultAppClass&||&(appClass&==&null))&{&&
&&&&&&&&appClass&=&"android.app.Application";&&
&&&&try&{&&
&&&&&&&&java.lang.ClassLoader&cl&=&getClassLoader();&&
&&&&&&&&ContextImpl&appContext&=&new&ContextImpl();&&
&&&&&&&&appContext.init(this,&null,&mActivityThread);&&
&&&&&&&&app&=&mActivityThread.mInstrumentation.newApplication(&&
&&&&&&&&&&&&&&&&cl,&appClass,&appContext);&&
&&&&&&&&appContext.setOuterContext(app);&&
&&&&}&catch&(Exception&e)&{&&
&&&&&&&&if&(!mActivityThread.mInstrumentation.onException(app,&e))&{&&
&&&&&&&&&&&&throw&new&RuntimeException(&&
&&&&&&&&&&&&&&&&"Unable&to&instantiate&application&"&+&appClass&&
&&&&&&&&&&&&&&&&+&":&"&+&e.toString(),&e);&&
&&&&&&&&}&&
看代码发现和Activity中ContextImpl的创建是相同的。
Service对象中ContextImpl的创建
通过查看代码发现和Activity、Application是一致的。分析到这里,那么三者的Context有什么区别呢?没有区别吗?尽管如此,有一些细节是确定的:Dialog的使用需要Activity,在桌面上我们采用Application的Context无法弹出对话框,同时在桌面上想启动新的activity,我们需要为intent设置FLAG_ACTIVITY_NEW_TASK标志,否则无法启动activity,这一切都说明,起码Application的Context和Activity的Context还是有区别的,当然这也可能不是Context的区别,因为在桌面上,我们的应用没有界面,这意味着我们能干的事情可能受到了限制,事情的细节目前我还没有搞的很清楚。
Context对资源的访问
很明确,不同的Context得到的都是同一份资源。这是很好理解的,请看下面的分析
得到资源的方式为context.getResources,而真正的实现位于ContextImpl中的getResources方法,在ContextImpl中有一个成员&private Resources mResources,它就是getResources方法返回的结果,mResources的赋值代码为:
mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),& & & & & & & & & & Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
下面看一下ResourcesManager的getTopLevelResources方法,这个方法的思想是这样的:在ResourcesManager中,所有的资源对象都被存储在ArrayMap中,首先根据当前的请求参数去查找资源,如果找到了就返回,否则就创建一个资源对象放到ArrayMap中。有一点需要说明的是为什么会有多个资源对象,原因很简单,因为res下可能存在多个适配不同设备、不同分辨率、不同系统版本的目录,按照android系统的设计,不同设备在访问同一个应用的时候访问的资源可以不同,比如drawable-hdpi和drawable-xhdpi就是典型的例子。&
public&Resources&getTopLevelResources(String&resDir,&int&displayId,&&
&&&&&&&&Configuration&overrideConfiguration,&CompatibilityInfo&compatInfo,&IBinder&token)&{&&
&&&&final&float&scale&=&compatInfo.applicationS&&
&&&&ResourcesKey&key&=&new&ResourcesKey(resDir,&displayId,&overrideConfiguration,&scale,&&
&&&&&&&&&&&&token);&&
&&&&Resources&r;&&
&&&&synchronized&(this)&{&&
&&&&&&&&if&(false)&{&&
&&&&&&&&&&&&Slog.w(TAG,&"getTopLevelResources:&"&+&resDir&+&"&/&"&+&scale);&&
&&&&&&&&}&&
&&&&&&&&WeakReference&Resources&&wr&=&mActiveResources.get(key);&&
&&&&&&&&r&=&wr&!=&null&?&wr.get()&:&&&
&&&&&&&&if&(r&!=&null&&&&r.getAssets().isUpToDate())&{&&
&&&&&&&&&&&&if&(false)&{&&
&&&&&&&&&&&&&&&&Slog.w(TAG,&"Returning&cached&resources&"&+&r&+&"&"&+&resDir&&
&&&&&&&&&&&&&&&&&&&&&&&&+&":&appScale="&+&r.getCompatibilityInfo().applicationScale);&&
&&&&&&&&&&&&}&&
&&&&&&&&&&&&return&r;&&
&&&&&&&&}&&
&&&&AssetManager&assets&=&new&AssetManager();&&
&&&&if&(assets.addAssetPath(resDir)&==&0)&{&&
&&&&&&&&return&&&
&&&&DisplayMetrics&dm&=&getDisplayMetricsLocked(displayId);&&
&&&&Configuration&&&
&&&&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()&:&&&
&&&&&&&&if&(existing&!=&null&&&&existing.getAssets().isUpToDate())&{&&
&&&&&&&&&&&&
&&&&&&&&&&&&
&&&&&&&&&&&&r.getAssets().close();&&
&&&&&&&&&&&&return&&&
&&&&&&&&}&&
&&&&&&&&mActiveResources.put(key,&new&WeakReference&Resources&(r));&&
&&&&&&&&return&r;&&
根据上述代码中资源的请求机制,再加上ResourcesManager采用单例模式,这样就保证了不同的ContextImpl访问的是同一套资源,注意,这里说的同一套资源未必是同一个资源,因为资源可能位于不同的目录,但它一定是我们的应用的资源,或许这样来描述更准确,在设备参数和显示参数不变的情况下,不同的ContextImpl访问到的是同一份资源。设备参数不变是指手机的屏幕和android版本不变,显示参数不变是指手机的分辨率和横竖屏状态。也就是说,尽管Application、Activity、Service都有自己的ContextImpl,并且每个ContextImpl都有自己的mResources成员,但是由于它们的mResources成员都来自于唯一的ResourcesManager实例,所以它们看似不同的mResources其实都指向的是同一块内存(C语言的概念),因此,它们的mResources都是同一个对象(在设备参数和显示参数不变的情况下)。在横竖屏切换的情况下且应用中为横竖屏状态提供了不同的资源,处在横屏状态下的ContextImpl和处在竖屏状态下的ContextImpl访问的资源不是同一个资源对象。
代码:单例模式的ResourcesManager类&
public&static&ResourcesManager&getInstance()&{&&
&&&&synchronized&(ResourcesManager.class)&{&&
&&&&&&&&if&(sResourcesManager&==&null)&{&&
&&&&&&&&&&&&sResourcesManager&=&new&ResourcesManager();&&
&&&&&&&&}&&
&&&&&&&&return&sResourcesM&&
getApplication和getApplicationContext的区别
getApplication返回结果为Application,且不同的Activity和Service返回的Application均为同一个全局对象,在ActivityThread内部有一个列表专门用于维护所有应用的application
& & final ArrayList&Application& mAllApplications& = new ArrayList&Application&();
getApplicationContext返回的也是Application对象,只不过返回类型为Context,看看它的实现
@Override&&
public&Context&getApplicationContext()&{&&
&&&&return&(mPackageInfo&!=&null)&?&&
&&&&&&&&&&&&mPackageInfo.getApplication()&:&mMainThread.getApplication();&&
上面代码中mPackageInfo是包含当前应用的包信息、比如包名、应用的安装目录等,原则上来说,作为第三方应用,包信息mPackageInfo不可能为空,在这种情况下,getApplicationContext返回的对象和getApplication是同一个。但是对于系统应用,包信息有可能为空,具体就不深入研究了。从这种角度来说,对于第三方应用,一个应用只存在一个Application对象,且通过getApplication和getApplicationContext得到的是同一个对象,两者的区别仅仅是返回类型不同。
应用中Context的数量
到此已经很明了了,一个应用中Context的数量等于Activity的个数&+ Service的个数&+ 1,这个1为Application。
阅读(...) 评论()问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
android getContext()、getApplicationContext()和this有什么区别
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
使用this, 说明当前类是context的子类,一般是activity application等
使用getApplicationContext 取得的是当前app所使用的application,这在AndroidManifest中唯一指定。意味着,在当前app的任意位置使用这个函数得到的是同一个Context
使用getContext获取的是当前对象所在的Context
Context通常翻译成上下文,我通常当成场景来理解。
比如 我在火车上。
This 指当前类就是当前的场景。我.this不是context,
我.getContext 是火车, 火车.this是一个context
AppContext 就可以理解成这个社会。发生的一切都在这个社会中.有且只有一个社会
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
同步到新浪微博
分享到微博?
Hi,欢迎来到 SegmentFault 技术社区!⊙▽⊙ 在这里,你可以提出编程相关的疑惑,关注感兴趣的问题,对认可的回答投赞同票;大家会帮你解决编程的问题,和你探讨技术更新,为你的回答投上赞同票。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 App
SegmentFault
一起探索更多未知

我要回帖

更多关于 activity getcontext 的文章

 

随机推荐