zoukankan      html  css  js  c++  java
  • 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对象。

  • 相关阅读:
    SQL COUNT() 语法
    SQL AVG 函数
    Android开发
    IIf 函数
    励志
    王者归来
    Java基础知识总结(绝对经典)
    LeetCode算法题-Third Maximum Number(Java实现-四种解法)
    LeetCode算法题-Fizz Buzz(Java实现)
    LeetCode算法题-Longest Palindrome(五种解法)
  • 原文地址:https://www.cnblogs.com/tsingke/p/9127758.html
Copyright © 2011-2022 走看看