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家族關系                                                                                           

1

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.NameNotFoundException;
    
    // 返回基於當前Context對象的新對象,其資源與display相匹配
    public abstract Context createDisplayContext(Display display);
 }

ContextImpl關鍵成員和函數                                                                          

/**
 * Common implementation of Context API, which provides the base
 * context object for Activity and other application components.
 */
class ContextImpl extends Context {
    private final static String TAG = "ContextImpl";
    private final static boolean DEBUG = false;

    private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
            new HashMap<String, SharedPreferencesImpl>();

    /*package*/ LoadedApk mPackageInfo; // 關鍵數據成員
    private String mBasePackageName;
    private Resources mResources;
    /*package*/ ActivityThread mMainThread; // 主線程

    @Override
    public AssetManager getAssets() {
        return getResources().getAssets();
    }

    @Override
    public Looper getMainLooper() {
        return mMainThread.getLooper();
    }

    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }

    @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();
        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                    + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                    + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
            getOuterContext(), mMainThread.getApplicationThread(), null,
            (Activity)null, intent, -1, options);
    }
}

ContextWrapper                                                                                        

它只是對Context類的一種封裝,它的構造函數包含了一個真正的Context引用,即ContextImpl對象。

/**
 * Proxying implementation of Context that simply delegates all of its calls to
 * another Context.  Can be subclassed to modify behavior without changing
 * the original Context.
 */
public class ContextWrapper extends Context {
    Context mBase; //該屬性指向一個ContextIml實例

    public ContextWrapper(Context base) {
        mBase = base;
    }

    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     * 創建Application、Service、Activity,會調用該方法給mBase屬性賦值
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    @Override
    public Looper getMainLooper() {
        return mBase.getMainLooper();
    }

    @Override
    public Object getSystemService(String name) {
        return mBase.getSystemService(name);
    }

    @Override
    public void startActivity(Intent intent) {
        mBase.startActivity(intent);
    }
}

ContextThemeWrapper                                                                            

該類內部包含了主題(Theme)相關的接口,即android:theme屬性指定的。只有Activity需要主題,Service不需要主題,所以Service直接繼承於ContextWrapper類。

/**
 * A ContextWrapper that allows you to modify the theme from what is in the 
 * wrapped context. 
 */
public class ContextThemeWrapper extends ContextWrapper {
    private Context mBase;
    private int mThemeResource;
    private Resources.Theme mTheme;
    private LayoutInflater mInflater;
    private Configuration mOverrideConfiguration;
    private Resources mResources;

    public ContextThemeWrapper() {
        super(null);
    }
    
    public ContextThemeWrapper(Context base, int themeres) {
        super(base);
        mBase = base;
        mThemeResource = themeres;
    }

    @Override protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        mBase = newBase;
    }

    @Override public void setTheme(int resid) {
        mThemeResource = resid;
        initializeTheme();
    }

    @Override public Resources.Theme getTheme() {
        if (mTheme != null) {
            return mTheme;
        }

        mThemeResource = Resources.selectDefaultTheme(mThemeResource,
                getApplicationInfo().targetSdkVersion);
        initializeTheme();

        return mTheme;
    }
}

何時創建Context                                                                         

應用程序在以下幾種情況下創建Context實例:

1) 創建Application 對象時, 而且整個App共一個Application對象

2) 創建Service對象時

3) 創建Activity對象時

因此應用程序App共有的Context數目公式為:

總Context實例個數 = Service個數 + Activity個數 + 1(Application對應的Context實例)

ActivityThread消息處理函數與本節相關的內容如下:

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: { // 創建Activity對象
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;

                case BIND_APPLICATION: // 創建Application對象
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
        
                case CREATE_SERVICE: // 創建Service對象
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                    
                case BIND_SERVICE:  // Bind Service對象
                    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.java
   private void handleBindApplication(AppBindData data) { 
      try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;
            ...
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
   }

   // LoadedApk.java
   public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        if (mApplication != null) {
            return mApplication;
        }

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            ContextImpl appContext = new ContextImpl(); // 創建ContextImpl實例
            appContext.init(this, null, mActivityThread);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app); // 將Application實例傳遞給Context實例
        } catch (Exception e) {
            ...
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        return app;
    }

創建Activity對象時創建Context實例                                                               

通過startActivity()或startActivityForResult()請求啟動一個Activity時,如果系統檢測需要新建一個Activity對象時,就會回調handleLaunchActivity()方法,該方法繼而調用performLaunchActivity()方法,去創建一個Activity實例,並且回調onCreate(),onStart()方法等,函數都位於 ActivityThread.java類 ,相關代碼如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity a = performLaunchActivity(r, customIntent); // 到下一步

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
            ...
        }
        ...
     }

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...    
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            ...
        }

        try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity); // 創建Context
                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 = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }


            mActivities.put(r.token, r);

        } catch (SuperNotCalledException e) {
            ...

        } catch (Exception e) {
            ...
        }

        return activity;
    }
private Context createBaseContextForActivity(ActivityClientRecord r,
            final Activity activity) {
        ContextImpl appContext = new ContextImpl();  // 創建ContextImpl實例
        appContext.init(r.packageInfo, r.token, this);
        appContext.setOuterContext(activity);

        // For debugging purposes, if the activity's package name contains the value of
        // the "debug.use-second-display" system property as a substring, then show
        // its content on a secondary display if there is one.
        Context baseContext = appContext;
        String pkgName = SystemProperties.get("debug.second-display.pkg");
        if (pkgName != null && !pkgName.isEmpty()
                && r.packageInfo.mPackageName.contains(pkgName)) {
            DisplayManagerGlobal dm = DisplayManagerGlobal.getInstance();
            for (int displayId : dm.getDisplayIds()) {
                if (displayId != Display.DEFAULT_DISPLAY) {
                    Display display = dm.getRealDisplay(displayId);
                    baseContext = appContext.createDisplayContext(display);
                    break;
                }
            }
        }
        return baseContext;
    }

創建Service對象時創建Context實例                                                               

通過startService或者bindService時,如果系統檢測到需要新創建一個Service實例,就會回調handleCreateService()方法,完成相關數據操作。handleCreateService()函數位於 ActivityThread.java類,如下:

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to instantiate service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = new ContextImpl(); // 創建ContextImpl實例
            context.init(packageInfo, null, this);

            Application app = 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 (RemoteException e) {
                // nothing to do.
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }

小結                                                                                            

通過對ContextImp的分析可知,其方法的大多數操作都是直接調用其屬性mPackageInfo(該屬性類型為PackageInfo)的相關方法而來。這說明ContextImp是一種輕量級類,而PackageInfo才是真正重量級的類。而一個App里的所有ContextImpl實例,都對應同一個packageInfo對象。

我是天王蓋地虎的分割線                                                                 

 

 

 

參考:http://blog.csdn.net/myarrow/article/details/14121757


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM