Android开发中Context类的作用以及Context的详细用法
Android中Context的作用以及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关键函数
1 public abstract class Context { 2 3 // 获取应用程序包的AssetManager实例 4 public abstract AssetManager getAssets(); 5 6 // 获取应用程序包的Resources实例 7 public abstract Resources getResources(); 8 9 // 获取PackageManager实例,以查看全局package信息 10 public abstract PackageManager getPackageManager(); 11 12 // 获取应用程序包的ContentResolver实例 13 public abstract ContentResolver getContentResolver(); 14 15 // 它返回当前进程的主线程的Looper,此线程分发调用给应用组件(activities, services等) 16 public abstract Looper getMainLooper(); 17 18 // 返回当前进程的单实例全局Application对象的Context 19 public abstract Context getApplicationContext(); 20 21 // 从string表中获取本地化的、格式化的字符序列 22 public final CharSequence getText(int resId) { 23 return getResources().getText(resId); 24 } 25 26 // 从string表中获取本地化的字符串 27 public final String getString(int resId) { 28 return getResources().getString(resId); 29 } 30 31 public final String getString(int resId, Object... formatArgs) { 32 return getResources().getString(resId, formatArgs); 33 } 34 35 // 返回一个可用于获取包中类信息的class loader 36 public abstract ClassLoader getClassLoader(); 37 38 // 返回应用程序包名 39 public abstract String getPackageName(); 40 41 // 返回应用程序信息 42 public abstract ApplicationInfo getApplicationInfo(); 43 44 // 根据文件名获取SharedPreferences 45 public abstract SharedPreferences getSharedPreferences(String name, 46 int mode); 47 48 // 其根目录为: Environment.getExternalStorageDirectory() 49 /* 50 * @param type The type of files directory to return. May be null for 51 * the root of the files directory or one of 52 * the following Environment constants for a subdirectory: 53 * {@link android.os.Environment#DIRECTORY_MUSIC}, 54 * {@link android.os.Environment#DIRECTORY_PODCASTS}, 55 * {@link android.os.Environment#DIRECTORY_RINGTONES}, 56 * {@link android.os.Environment#DIRECTORY_ALARMS}, 57 * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, 58 * {@link android.os.Environment#DIRECTORY_PICTURES}, or 59 * {@link android.os.Environment#DIRECTORY_MOVIES}. 60 */ 61 public abstract File getExternalFilesDir(String type); 62 63 // 返回应用程序obb文件路径 64 public abstract File getObbDir(); 65 66 // 启动一个新的activity 67 public abstract void startActivity(Intent intent); 68 69 // 启动一个新的activity 70 public void startActivityAsUser(Intent intent, UserHandle user) { 71 throw new RuntimeException("Not implemented. Must override in a subclass."); 72 } 73 74 // 启动一个新的activity 75 // intent: 将被启动的activity的描述信息 76 // options: 描述activity将如何被启动 77 public abstract void startActivity(Intent intent, Bundle options); 78 79 // 启动多个新的activity 80 public abstract void startActivities(Intent[] intents); 81 82 // 启动多个新的activity 83 public abstract void startActivities(Intent[] intents, Bundle options); 84 85 // 广播一个intent给所有感兴趣的接收者,异步机制 86 public abstract void sendBroadcast(Intent intent); 87 88 // 广播一个intent给所有感兴趣的接收者,异步机制 89 public abstract void sendBroadcast(Intent intent,String receiverPermission); 90 91 public abstract void sendOrderedBroadcast(Intent intent,String receiverPermission); 92 93 public abstract void sendOrderedBroadcast(Intent intent, 94 String receiverPermission, BroadcastReceiver resultReceiver, 95 Handler scheduler, int initialCode, String initialData, 96 Bundle initialExtras); 97 98 public abstract void sendBroadcastAsUser(Intent intent, UserHandle user); 99 100 public abstract void sendBroadcastAsUser(Intent intent, UserHandle user, 101 String receiverPermission); 102 103 // 注册一个BroadcastReceiver,且它将在主activity线程中运行 104 public abstract Intent registerReceiver(BroadcastReceiver receiver, 105 IntentFilter filter); 106 107 public abstract Intent registerReceiver(BroadcastReceiver receiver, 108 IntentFilter filter, String broadcastPermission, Handler scheduler); 109 110 public abstract void unregisterReceiver(BroadcastReceiver receiver); 111 112 // 请求启动一个application service 113 public abstract ComponentName startService(Intent service); 114 115 // 请求停止一个application service 116 public abstract boolean stopService(Intent service); 117 118 // 连接一个应用服务,它定义了application和service间的依赖关系 119 public abstract boolean bindService(Intent service, ServiceConnection conn, 120 int flags); 121 122 // 断开一个应用服务,当服务重新开始时,将不再接收到调用, 123 // 且服务允许随时停止 124 public abstract void unbindService(ServiceConnection conn); 125 126 // 返回系统级service句柄 127 /* 128 * @see #WINDOW_SERVICE 129 * @see android.view.WindowManager 130 * @see #LAYOUT_INFLATER_SERVICE 131 * @see android.view.LayoutInflater 132 * @see #ACTIVITY_SERVICE 133 * @see android.app.ActivityManager 134 * @see #POWER_SERVICE 135 * @see android.os.PowerManager 136 * @see #ALARM_SERVICE 137 * @see android.app.AlarmManager 138 * @see #NOTIFICATION_SERVICE 139 * @see android.app.NotificationManager 140 * @see #KEYGUARD_SERVICE 141 * @see android.app.KeyguardManager 142 * @see #LOCATION_SERVICE 143 * @see android.location.LocationManager 144 * @see #SEARCH_SERVICE 145 * @see android.app.SearchManager 146 * @see #SENSOR_SERVICE 147 * @see android.hardware.SensorManager 148 * @see #STORAGE_SERVICE 149 * @see android.os.storage.StorageManager 150 * @see #VIBRATOR_SERVICE 151 * @see android.os.Vibrator 152 * @see #CONNECTIVITY_SERVICE 153 * @see android.net.ConnectivityManager 154 * @see #WIFI_SERVICE 155 * @see android.net.wifi.WifiManager 156 * @see #AUDIO_SERVICE 157 * @see android.media.AudioManager 158 * @see #MEDIA_ROUTER_SERVICE 159 * @see android.media.MediaRouter 160 * @see #TELEPHONY_SERVICE 161 * @see android.telephony.TelephonyManager 162 * @see #INPUT_METHOD_SERVICE 163 * @see android.view.inputmethod.InputMethodManager 164 * @see #UI_MODE_SERVICE 165 * @see android.app.UiModeManager 166 * @see #DOWNLOAD_SERVICE 167 * @see android.app.DownloadManager 168 */ 169 public abstract Object getSystemService(String name); 170 171 public abstract int checkPermission(String permission, int pid, int uid); 172 173 // 返回一个新的与application name对应的Context对象 174 public abstract Context createPackageContext(String packageName, 175 int flags) throws PackageManager.NameNotFoundException; 176 177 // 返回基于当前Context对象的新对象,其资源与display相匹配 178 public abstract Context createDisplayContext(Display display); 179 }
ContextImpl关键成员和函数
1 /** 2 * Common implementation of Context API, which provides the base 3 * context object for Activity and other application components. 4 */ 5 class ContextImpl extends Context { 6 private final static String TAG = "ContextImpl"; 7 private final static boolean DEBUG = false; 8 9 private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs = 10 new HashMap<String, SharedPreferencesImpl>(); 11 12 /*package*/ LoadedApk mPackageInfo; // 关键数据成员 13 private String mBasePackageName; 14 private Resources mResources; 15 /*package*/ ActivityThread mMainThread; // 主线程 16 17 @Override 18 public AssetManager getAssets() { 19 return getResources().getAssets(); 20 } 21 22 @Override 23 public Looper getMainLooper() { 24 return mMainThread.getLooper(); 25 } 26 27 @Override 28 public Object getSystemService(String name) { 29 ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); 30 return fetcher == null ? null : fetcher.getService(this); 31 } 32 33 @Override 34 public void startActivity(Intent intent, Bundle options) { 35 warnIfCallingFromSystemProcess(); 36 if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { 37 throw new AndroidRuntimeException( 38 "Calling startActivity() from outside of an Activity " 39 + " context requires the FLAG_ACTIVITY_NEW_TASK flag." 40 + " Is this really what you want?"); 41 } 42 mMainThread.getInstrumentation().execStartActivity( 43 getOuterContext(), mMainThread.getApplicationThread(), null, 44 (Activity)null, intent, -1, options); 45 } 46 }
ContextWrapper
它只是对Context类的一种封装,它的构造函数包含了一个真正的Context引用,即ContextImpl对象。
1 /** 2 * Proxying implementation of Context that simply delegates all of its calls to 3 * another Context. Can be subclassed to modify behavior without changing 4 * the original Context. 5 */ 6 public class ContextWrapper extends Context { 7 Context mBase; //该属性指向一个ContextIml实例 8 9 public ContextWrapper(Context base) { 10 mBase = base; 11 } 12 13 /** 14 * Set the base context for this ContextWrapper. All calls will then be 15 * delegated to the base context. Throws 16 * IllegalStateException if a base context has already been set. 17 * 18 * @param base The new base context for this wrapper. 19 * 创建Application、Service、Activity,会调用该方法给mBase属性赋值 20 */ 21 protected void attachBaseContext(Context base) { 22 if (mBase != null) { 23 throw new IllegalStateException("Base context already set"); 24 } 25 mBase = base; 26 } 27 28 @Override 29 public Looper getMainLooper() { 30 return mBase.getMainLooper(); 31 } 32 33 @Override 34 public Object getSystemService(String name) { 35 return mBase.getSystemService(name); 36 } 37 38 @Override 39 public void startActivity(Intent intent) { 40 mBase.startActivity(intent); 41 } 42 }
ContextThemeWrapper
该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。只有Activity需要主题,Service不需要主题,所以Service直接继承于ContextWrapper类。
1 /** 2 * A ContextWrapper that allows you to modify the theme from what is in the 3 * wrapped context. 4 */ 5 public class ContextThemeWrapper extends ContextWrapper { 6 private Context mBase; 7 private int mThemeResource; 8 private Resources.Theme mTheme; 9 private LayoutInflater mInflater; 10 private Configuration mOverrideConfiguration; 11 private Resources mResources; 12 13 public ContextThemeWrapper() { 14 super(null); 15 } 16 17 public ContextThemeWrapper(Context base, int themeres) { 18 super(base); 19 mBase = base; 20 mThemeResource = themeres; 21 } 22 23 @Override protected void attachBaseContext(Context newBase) { 24 super.attachBaseContext(newBase); 25 mBase = newBase; 26 } 27 28 @Override public void setTheme(int resid) { 29 mThemeResource = resid; 30 initializeTheme(); 31 } 32 33 @Override public Resources.Theme getTheme() { 34 if (mTheme != null) { 35 return mTheme; 36 } 37 38 mThemeResource = Resources.selectDefaultTheme(mThemeResource, 39 getApplicationInfo().targetSdkVersion); 40 initializeTheme(); 41 42 return mTheme; 43 } 44 }
何时创建Context
应用程序在以下几种情况下创建Context实例:
1) 创建Application 对象时, 而且整个App共一个Application对象
2) 创建Service对象时
3) 创建Activity对象时
因此应用程序App共有的Context数目公式为:
总Context实例个数 = Service个数 + Activity个数 + 1(Application对应的Context实例)
ActivityThread消息处理函数与本节相关的内容如下:
1 public void handleMessage(Message msg) { 2 if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); 3 switch (msg.what) { 4 case LAUNCH_ACTIVITY: { // 创建Activity对象 5 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); 6 ActivityClientRecord r = (ActivityClientRecord)msg.obj; 7 8 r.packageInfo = getPackageInfoNoCheck( 9 r.activityInfo.applicationInfo, r.compatInfo); 10 handleLaunchActivity(r, null); 11 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 12 } break; 13 14 case BIND_APPLICATION: // 创建Application对象 15 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication"); 16 AppBindData data = (AppBindData)msg.obj; 17 handleBindApplication(data); 18 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 19 break; 20 21 case CREATE_SERVICE: // 创建Service对象 22 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate"); 23 handleCreateService((CreateServiceData)msg.obj); 24 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 25 break; 26 27 case BIND_SERVICE: // Bind Service对象 28 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind"); 29 handleBindService((BindServiceData)msg.obj); 30 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); 31 break; 32 } 33 }
创建Application对象时创建Context实例
每个应用程序在第一次启动时,都会首先创建一个Application对象。从startActivity流程可知,创建Application的时机在handleBindApplication()方法中,该函数位于 ActivityThread.java类中 ,相关代码如下:
1 // ActivityThread.java 2 private void handleBindApplication(AppBindData data) { 3 try { 4 // If the app is being launched for full backup or restore, bring it up in 5 // a restricted environment with the base application class. 6 Application app = data.info.makeApplication(data.restrictedBackupMode, null); 7 mInitialApplication = app; 8 ... 9 } finally { 10 StrictMode.setThreadPolicy(savedPolicy); 11 } 12 } 13 14 // LoadedApk.java 15 public Application makeApplication(boolean forceDefaultAppClass, 16 Instrumentation instrumentation) { 17 if (mApplication != null) { 18 return mApplication; 19 } 20 21 Application app = null; 22 23 String appClass = mApplicationInfo.className; 24 if (forceDefaultAppClass || (appClass == null)) { 25 appClass = "android.app.Application"; 26 } 27 28 try { 29 java.lang.ClassLoader cl = getClassLoader(); 30 ContextImpl appContext = new ContextImpl(); // 创建ContextImpl实例 31 appContext.init(this, null, mActivityThread); 32 app = mActivityThread.mInstrumentation.newApplication( 33 cl, appClass, appContext); 34 appContext.setOuterContext(app); // 将Application实例传递给Context实例 35 } catch (Exception e) { 36 ... 37 } 38 mActivityThread.mAllApplications.add(app); 39 mApplication = app; 40 41 return app; 42 } 43 private Context createBaseContextForActivity(ActivityClientRecord r, 44 final Activity activity) { 45 ContextImpl appContext = new ContextImpl(); // 创建ContextImpl实例 46 appContext.init(r.packageInfo, r.token, this); 47 appContext.setOuterContext(activity); 48 49 // For debugging purposes, if the activity's package name contains the value of 50 // the "debug.use-second-display" system property as a substring, then show 51 // its content on a secondary display if there is one. 52 Context baseContext = appContext; 53 String pkgName = SystemProperties.get("debug.second-display.pkg"); 54 if (pkgName != null && !pkgName.isEmpty() 55 && r.packageInfo.mPackageName.contains(pkgName)) { 56 DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance(); 57 for (int displayId : dm.getDisplayIds()) { 58 if (displayId != Display.DEFAULT_DISPLAY) { 59 Display display = dm.getRealDisplay(displayId); 60 baseContext = appContext.createDisplayContext(display); 61 break; 62 } 63 } 64 } 65 return baseContext; 66 }
创建Service对象时创建Context实例
通过startService或者bindService时,如果系统检测到需要新创建一个Service实例,就会回调handleCreateService()方法,完成相关数据操作。handleCreateService()函数位于 ActivityThread.java类,如下:
1 private void handleCreateService(CreateServiceData data) { 2 // If we are getting ready to gc after going to the background, well 3 // we are back active so skip it. 4 unscheduleGcIdler(); 5 6 LoadedApk packageInfo = getPackageInfoNoCheck( 7 data.info.applicationInfo, data.compatInfo); 8 Service service = null; 9 try { 10 java.lang.ClassLoader cl = packageInfo.getClassLoader(); 11 service = (Service) cl.loadClass(data.info.name).newInstance(); 12 } catch (Exception e) { 13 if (!mInstrumentation.onException(service, e)) { 14 throw new RuntimeException( 15 "Unable to instantiate service " + data.info.name 16 + ": " + e.toString(), e); 17 } 18 } 19 20 try { 21 if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); 22 23 ContextImpl context = new ContextImpl(); // 创建ContextImpl实例 24 context.init(packageInfo, null, this); 25 26 Application app = packageInfo.makeApplication(false, mInstrumentation); 27 context.setOuterContext(service); 28 service.attach(context, this, data.info.name, data.token, app, 29 ActivityManagerNative.getDefault()); 30 service.onCreate(); 31 mServices.put(data.token, service); 32 try { 33 ActivityManagerNative.getDefault().serviceDoneExecuting( 34 data.token, 0, 0, 0); 35 } catch (RemoteException e) { 36 // nothing to do. 37 } 38 } catch (Exception e) { 39 if (!mInstrumentation.onException(service, e)) { 40 throw new RuntimeException( 41 "Unable to create service " + data.info.name 42 + ": " + e.toString(), e); 43 } 44 } 45 }
1 private void handleCreateService(CreateServiceData data) { 2 // If we are getting ready to gc after going to the background, well 3 // we are back active so skip it. 4 unscheduleGcIdler(); 5 6 LoadedApk packageInfo = getPackageInfoNoCheck( 7 data.info.applicationInfo, data.compatInfo); 8 Service service = null; 9 try { 10 java.lang.ClassLoader cl = packageInfo.getClassLoader(); 11 service = (Service) cl.loadClass(data.info.name).newInstance(); 12 } catch (Exception e) { 13 if (!mInstrumentation.onException(service, e)) { 14 throw new RuntimeException( 15 "Unable to instantiate service " + data.info.name 16 + ": " + e.toString(), e); 17 } 18 } 19 20 try { 21 if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); 22 23 ContextImpl context = new ContextImpl(); // 创建ContextImpl实例 24 context.init(packageInfo, null, this); 25 26 Application app = packageInfo.makeApplication(false, mInstrumentation); 27 context.setOuterContext(service); 28 service.attach(context, this, data.info.name, data.token, app, 29 ActivityManagerNative.getDefault()); 30 service.onCreate(); 31 mServices.put(data.token, service); 32 try { 33 ActivityManagerNative.getDefault().serviceDoneExecuting( 34 data.token, 0, 0, 0); 35 } catch (RemoteException e) { 36 // nothing to do. 37 } 38 } catch (Exception e) { 39 if (!mInstrumentation.onException(service, e)) { 40 throw new RuntimeException( 41 "Unable to create service " + data.info.name 42 + ": " + e.toString(), e); 43 } 44 } 45 }
小结
通过对ContextImp的分析可知,其方法的大多数操作都是直接调用其属性mPackageInfo(该属性类型为PackageInfo)的相关方法而来。这说明ContextImp是一种轻量级类,而PackageInfo才是真正重量级的类。而一个App里的所有ContextImpl实例,都对应同一个packageInfo对象。