关注微信号:javalearns 随时随地学Java

或扫一扫

随时随地学Java

本文我们一起来探讨一下关于Android中Context的作用以及Context的详细用法,这对我们学习Android的资源访问有很大的帮助,文章中也贴出了一些关于Android Context使用的示例代码,非常不错,以下是原文:

Context基本概念

Context是什么?

1) Context是一个抽象类,其通用实现在ContextImpl类中。

2) Context:是一个访问application环境全局信息的接口,通过它可以访问application的资源和相关的类,其主要功能如下:

启动Activity
启动和停止Service
发送广播消息(Intent)
注册广播消息(Intent)接收者
可以访问APK中各种资源(如Resources和AssetManager等)
可以访问Package的相关信息
APK的各种权限管理

从以上分析可以看出,Context就是一个对APK包无所不知的大管家,大家需要什么,直接问它就可以了。

Context与View的关系

View与Context(或Activity)的关系类似于明星与经纪人的关系,所以创建View时,必须明确指定其Context(即经纪人或大管家),否则View就成不了明星。

Context家族关系

Context关键函数

publicabstractclassContext{//获取应用程序包的AssetManager实例publicabstractAssetManagergetAssets();//获取应用程序包的Resources实例publicabstractResourcesgetResources();//获取PackageManager实例,以查看全局package信息publicabstractPackageManagergetPackageManager();//获取应用程序包的ContentResolver实例publicabstractContentResolvergetContentResolver();//它返回当前进程的主线程的Looper,此线程分发调用给应用组件(activities,services等)publicabstractLoopergetMainLooper();//返回当前进程的单实例全局Application对象的ContextpublicabstractContextgetApplicationContext();//从string表中获取本地化的、格式化的字符序列publicfinalCharSequencegetText(intresId){returngetResources().getText(resId);}//从string表中获取本地化的字符串publicfinalStringgetString(intresId){returngetResources().getString(resId);}publicfinalStringgetString(intresId,Object...formatArgs){returngetResources().getString(resId,formatArgs);}//返回一个可用于获取包中类信息的classloaderpublicabstractClassLoadergetClassLoader();//返回应用程序包名publicabstractStringgetPackageName();//返回应用程序信息publicabstractApplicationInfogetApplicationInfo();//根据文件名获取SharedPreferencespublicabstractSharedPreferencesgetSharedPreferences(Stringname,intmode);//其根目录为:Environment.getExternalStorageDirectory()/**@paramtypeThetypeoffilesdirectorytoreturn.Maybenullfor*therootofthefilesdirectoryoroneof*thefollowingEnvironmentconstantsforasubdirectory:*{@linkandroid.os.Environment#DIRECTORY_MUSIC},*{@linkandroid.os.Environment#DIRECTORY_PODCASTS},*{@linkandroid.os.Environment#DIRECTORY_RINGTONES},*{@linkandroid.os.Environment#DIRECTORY_ALARMS},*{@linkandroid.os.Environment#DIRECTORY_NOTIFICATIONS},*{@linkandroid.os.Environment#DIRECTORY_PICTURES},or*{@linkandroid.os.Environment#DIRECTORY_MOVIES}.*/publicabstractFilegetExternalFilesDir(Stringtype);//返回应用程序obb文件路径publicabstractFilegetObbDir();//启动一个新的activitypublicabstractvoidstartActivity(Intentintent);//启动一个新的activitypublicvoidstartActivityAsUser(Intentintent,UserHandleuser){thrownewRuntimeException("Notimplemented.Mustoverrideinasubclass.");}//启动一个新的activity//intent:将被启动的activity的描述信息//options:描述activity将如何被启动publicabstractvoidstartActivity(Intentintent,Bundleoptions);//启动多个新的activitypublicabstractvoidstartActivities(Intent[]intents);//启动多个新的activitypublicabstractvoidstartActivities(Intent[]intents,Bundleoptions);//广播一个intent给所有感兴趣的接收者,异步机制publicabstractvoidsendBroadcast(Intentintent);//广播一个intent给所有感兴趣的接收者,异步机制publicabstractvoidsendBroadcast(Intentintent,StringreceiverPermission);publicabstractvoidsendOrderedBroadcast(Intentintent,StringreceiverPermission);publicabstractvoidsendOrderedBroadcast(Intentintent,StringreceiverPermission,BroadcastReceiverresultReceiver,Handlerscheduler,intinitialCode,StringinitialData,BundleinitialExtras);publicabstractvoidsendBroadcastAsUser(Intentintent,UserHandleuser);publicabstractvoidsendBroadcastAsUser(Intentintent,UserHandleuser,StringreceiverPermission);//注册一个BroadcastReceiver,且它将在主activity线程中运行publicabstractIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter);publicabstractIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter,StringbroadcastPermission,Handlerscheduler);publicabstractvoidunregisterReceiver(BroadcastReceiverreceiver);//请求启动一个applicationservicepublicabstractComponentNamestartService(Intentservice);//请求停止一个applicationservicepublicabstractbooleanstopService(Intentservice);//连接一个应用服务,它定义了application和service间的依赖关系publicabstractbooleanbindService(Intentservice,ServiceConnectionconn,intflags);//断开一个应用服务,当服务重新开始时,将不再接收到调用,//且服务允许随时停止publicabstractvoidunbindService(ServiceConnectionconn);//返回系统级service句柄/**@see#WINDOW_SERVICE*@seeandroid.view.WindowManager*@see#LAYOUT_INFLATER_SERVICE*@seeandroid.view.LayoutInflater*@see#ACTIVITY_SERVICE*@seeandroid.app.ActivityManager*@see#POWER_SERVICE*@seeandroid.os.PowerManager*@see#ALARM_SERVICE*@seeandroid.app.AlarmManager*@see#NOTIFICATION_SERVICE*@seeandroid.app.NotificationManager*@see#KEYGUARD_SERVICE*@seeandroid.app.KeyguardManager*@see#LOCATION_SERVICE*@seeandroid.location.LocationManager*@see#SEARCH_SERVICE*@seeandroid.app.SearchManager*@see#SENSOR_SERVICE*@seeandroid.hardware.SensorManager*@see#STORAGE_SERVICE*@seeandroid.os.storage.StorageManager*@see#VIBRATOR_SERVICE*@seeandroid.os.Vibrator*@see#CONNECTIVITY_SERVICE*@seeandroid.net.ConnectivityManager*@see#WIFI_SERVICE*@seeandroid.net.wifi.WifiManager*@see#AUDIO_SERVICE*@seeandroid.media.AudioManager*@see#MEDIA_ROUTER_SERVICE*@seeandroid.media.MediaRouter*@see#TELEPHONY_SERVICE*@seeandroid.telephony.TelephonyManager*@see#INPUT_METHOD_SERVICE*@seeandroid.view.inputmethod.InputMethodManager*@see#UI_MODE_SERVICE*@seeandroid.app.UiModeManager*@see#DOWNLOAD_SERVICE*@seeandroid.app.DownloadManager*/publicabstractObjectgetSystemService(Stringname);publicabstractintcheckPermission(Stringpermission,intpid,intuid);//返回一个新的与applicationname对应的Context对象publicabstractContextcreatePackageContext(StringpackageName,intflags)throwsPackageManager.NameNotFoundException;//返回基于当前Context对象的新对象,其资源与display相匹配publicabstractContextcreateDisplayContext(Displaydisplay);}

ContextImpl关键成员和函数

/***CommonimplementationofContextAPI,whichprovidesthebase*contextobjectforActivityandotherapplicationcomponents.*/classContextImplextendsContext{privatefinalstaticStringTAG="ContextImpl";privatefinalstaticbooleanDEBUG=false;privatestaticfinalHashMap<String,SharedPreferencesImpl>sSharedPrefs=newHashMap<String,SharedPreferencesImpl>();/*package*/LoadedApkmPackageInfo;//关键数据成员privateStringmBasePackageName;privateResourcesmResources;/*package*/ActivityThreadmMainThread;//主线程@OverridepublicAssetManagergetAssets(){returngetResources().getAssets();}@OverridepublicLoopergetMainLooper(){returnmMainThread.getLooper();}@OverridepublicObjectgetSystemService(Stringname){ServiceFetcherfetcher=SYSTEM_SERVICE_MAP.get(name);returnfetcher==null?null:fetcher.getService(this);}@OverridepublicvoidstartActivity(Intentintent,Bundleoptions){warnIfCallingFromSystemProcess();if((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK)==0){thrownewAndroidRuntimeException("CallingstartActivity()fromoutsideofanActivity"+"contextrequirestheFLAG_ACTIVITY_NEW_TASKflag."+"Isthisreallywhatyouwant?");}mMainThread.getInstrumentation().execStartActivity(getOuterContext(),mMainThread.getApplicationThread(),null,(Activity)null,intent,-1,options);}}

ContextWrapper

它只是对Context类的一种封装,它的构造函数包含了一个真正的Context引用,即ContextImpl对象。

/***ProxyingimplementationofContextthatsimplydelegatesallofitscallsto*anotherContext.Canbesubclassedtomodifybehaviorwithoutchanging*theoriginalContext.*/publicclassContextWrapperextendsContext{ContextmBase;//该属性指向一个ContextIml实例publicContextWrapper(Contextbase){mBase=base;}/***SetthebasecontextforthisContextWrapper.Allcallswillthenbe*delegatedtothebasecontext.Throws*IllegalStateExceptionifabasecontexthasalreadybeenset.**@parambaseThenewbasecontextforthiswrapper.*创建Application、Service、Activity,会调用该方法给mBase属性赋值*/protectedvoidattachBaseContext(Contextbase){if(mBase!=null){thrownewIllegalStateException("Basecontextalreadyset");}mBase=base;}@OverridepublicLoopergetMainLooper(){returnmBase.getMainLooper();}@OverridepublicObjectgetSystemService(Stringname){returnmBase.getSystemService(name);}@OverridepublicvoidstartActivity(Intentintent){mBase.startActivity(intent);}}

ContextThemeWrapper

该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。只有Activity需要主题,Service不需要主题,所以Service直接继承于ContextWrapper类。

/***AContextWrapperthatallowsyoutomodifythethemefromwhatisinthe*wrappedcontext.*/publicclassContextThemeWrapperextendsContextWrapper{privateContextmBase;privateintmThemeResource;privateResources.ThememTheme;privateLayoutInflatermInflater;privateConfigurationmOverrideConfiguration;privateResourcesmResources;publicContextThemeWrapper(){super(null);}publicContextThemeWrapper(Contextbase,intthemeres){super(base);mBase=base;mThemeResource=themeres;}@OverrideprotectedvoidattachBaseContext(ContextnewBase){super.attachBaseContext(newBase);mBase=newBase;}@OverridepublicvoidsetTheme(intresid){mThemeResource=resid;initializeTheme();}@OverridepublicResources.ThemegetTheme(){if(mTheme!=null){returnmTheme;}mThemeResource=Resources.selectDefaultTheme(mThemeResource,getApplicationInfo().targetSdkVersion);initializeTheme();returnmTheme;}}

何时创建Context

应用程序在以下几种情况下创建Context实例:

1) 创建Application 对象时, 而且整个App共一个Application对象

2) 创建Service对象时

3) 创建Activity对象时

因此应用程序App共有的Context数目公式为:

总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)

ActivityThread消息处理函数与本节相关的内容如下:

publicvoidhandleMessage(Messagemsg){if(DEBUG_MESSAGES)Slog.v(TAG,">>>handling:"+codeToString(msg.what));switch(msg.what){caseLAUNCH_ACTIVITY:{//创建Activity对象Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"activityStart");ActivityClientRecordr=(ActivityClientRecord)msg.obj;r.packageInfo=getPackageInfoNoCheck(r.activityInfo.applicationInfo,r.compatInfo);handleLaunchActivity(r,null);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}break;caseBIND_APPLICATION://创建Application对象Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"bindApplication");AppBindDatadata=(AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;caseCREATE_SERVICE://创建Service对象Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"serviceCreate");handleCreateService((CreateServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;caseBIND_SERVICE://BindService对象Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"serviceBind");handleBindService((BindServiceData)msg.obj);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;}}

创建Application对象时创建Context实例

每个应用程序在第一次启动时,都会首先创建一个Application对象。从startActivity流程可知,创建Application的时机在handleBindApplication()方法中,该函数位于 ActivityThread.java类中 ,相关代码如下:

//ActivityThread.javaprivatevoidhandleBindApplication(AppBindDatadata){try{//Iftheappisbeinglaunchedforfullbackuporrestore,bringitupin//arestrictedenvironmentwiththebaseapplicationclass.Applicationapp=data.info.makeApplication(data.restrictedBackupMode,null);mInitialApplication=app;...}finally{StrictMode.setThreadPolicy(savedPolicy);}}//LoadedApk.javapublicApplicationmakeApplication(booleanforceDefaultAppClass,Instrumentationinstrumentation){if(mApplication!=null){returnmApplication;}Applicationapp=null;StringappClass=mApplicationInfo.className;if(forceDefaultAppClass||(appClass==null)){appClass="android.app.Application";}try{java.lang.ClassLoadercl=getClassLoader();ContextImplappContext=newContextImpl();//创建ContextImpl实例appContext.init(this,null,mActivityThread);app=mActivityThread.mInstrumentation.newApplication(cl,appClass,appContext);appContext.setOuterContext(app);//将Application实例传递给Context实例}catch(Exceptione){...}mActivityThread.mAllApplications.add(app);mApplication=app;returnapp;}
privateContextcreateBaseContextForActivity(ActivityClientRecordr,finalActivityactivity){ContextImplappContext=newContextImpl();//创建ContextImpl实例appContext.init(r.packageInfo,r.token,this);appContext.setOuterContext(activity);//Fordebuggingpurposes,iftheactivity'spackagenamecontainsthevalueof//the"debug.use-second-display"systempropertyasasubstring,thenshow//itscontentonasecondarydisplayifthereisone.ContextbaseContext=appContext;StringpkgName=SystemProperties.get("debug.second-display.pkg");if(pkgName!=null&&!pkgName.isEmpty()&&r.packageInfo.mPackageName.contains(pkgName)){DisplayManagerGlobaldm=DisplayManagerGlobal.getInstance();for(intdisplayId:dm.getDisplayIds()){if(displayId!=Display.DEFAULT_DISPLAY){Displaydisplay=dm.getRealDisplay(displayId);baseContext=appContext.createDisplayContext(display);break;}}}returnbaseContext;}

创建Service对象时创建Context实例

通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,如下:

privatevoidhandleCreateService(CreateServiceDatadata){//Ifwearegettingreadytogcaftergoingtothebackground,well//wearebackactivesoskipit.unscheduleGcIdler();LoadedApkpackageInfo=getPackageInfoNoCheck(data.info.applicationInfo,data.compatInfo);Serviceservice=null;try{java.lang.ClassLoadercl=packageInfo.getClassLoader();service=(Service)cl.loadClass(data.info.name).newInstance();}catch(Exceptione){if(!mInstrumentation.onException(service,e)){thrownewRuntimeException("Unabletoinstantiateservice"+data.info.name+":"+e.toString(),e);}}try{if(localLOGV)Slog.v(TAG,"Creatingservice"+data.info.name);ContextImplcontext=newContextImpl();//创建ContextImpl实例context.init(packageInfo,null,this);Applicationapp=packageInfo.makeApplication(false,mInstrumentation);context.setOuterContext(service);service.attach(context,this,data.info.name,data.token,app,ActivityManagerNative.getDefault());service.onCreate();mServices.put(data.token,service);try{ActivityManagerNative.getDefault().serviceDoneExecuting(data.token,0,0,0);}catch(RemoteExceptione){//nothingtodo.}}catch(Exceptione){if(!mInstrumentation.onException(service,e)){thrownewRuntimeException("Unabletocreateservice"+data.info.name+":"+e.toString(),e);}}}

小结

通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的所有ContextImpl实例,都对应同一个packageInfo对象。

关注微信号:javalearns 随时随地学Java

或扫一扫

随时随地学Java

更多相关文章

  1. android内存分析工具- MAT的初识(1)
  2. 初步理解Android(安卓)Fragment
  3. Android智能指针SP WP使用方法介绍
  4. Android之Intent原理
  5. Android(安卓)开发必读:如何成为一名优秀的Android开发者
  6. 关于AVD启动失败的问题--找不到文件篇
  7. 创建Android虚拟设备(AVD)
  8. Android(安卓)使用Parcelable传递对象
  9. Android(安卓)网络编程之网络通信几种方式实例分享

随机推荐

  1. Android(安卓)实现滑动方法总结
  2. Android(安卓)UI 之WaterFall瀑布流效果
  3. Android开发之手机震动器
  4. listView下拉刷新(仿sina微博Android客户
  5. 解决API
  6. 对话框的练习(android)
  7. android中的sqlit3数据库进行手机应用软
  8. RelativeLayout布局,以及部分常用属性介绍
  9. android 隐藏虚拟按键
  10. [转]Android中Matrix的pre post set方法