博客出處java
前言:本文是我讀《Android內核剖析》第7章 後造成的讀書筆記 ,在此向欲瞭解Android框架的書籍推薦此書。android
你們好, 今天給你們介紹下咱們在應用開發中最熟悉而陌生的朋友-----Context類 ,說它熟悉,是應爲咱們在開發中
時刻的在與它打交道,例如:Service、BroadcastReceiver、Activity等都會利用到Context的相關方法 ; 說它陌生,徹底是
由於咱們真正的不懂Context的原理、類結構關係。一個簡單的問題是,一個應用程序App中存在多少個Context實例對象呢?
一個、兩個? 在此先賣個關子吧。讀了本文,相信您會豁然開朗的 。app
Context,中文直譯爲「上下文」,SDK中對其說明以下:
Interface to global information about an application environment. This is an abstract class whose implementation
is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls
for application-level operations such as launching activities, broadcasting and receiving intents, etc框架
從上可知一下三點,即:
一、它描述的是一個應用程序環境的信息,即上下文。
二、該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實現類(後面咱們會講到是ContextIml類)。
三、經過它咱們能夠獲取應用程序的資源和類,也包括一些應用級別操做,例如:啓動一個Activity,發送廣播,接受Intent信息 等。。ide
因而,咱們能夠利用該Context對象去構建應用級別操做(application-level operations) 。函數
路徑: /frameworks/base/core/Java/android/content/Context.java
說明: 抽象類,提供了一組通用的API。
源代碼(部分)以下:
[java] view plain copy print?學習
public abstract class Context { ... public abstract Object getSystemService(String name); //得到系統級服務 public abstract void startActivity(Intent intent); //經過一個Intent啓動Activity public abstract ComponentName startService(Intent service); //啓動Service //根據文件名獲得SharedPreferences對象 public abstract SharedPreferences getSharedPreferences(String name,int mode); ... }
路徑 :/frameworks/base/core/java/android/app/ContextImpl.java
說明:該Context類的實現類爲ContextIml,該類實現了Context類的功能。請注意,該函數的大部分功能都是直接調用
其屬性mPackageInfo去完成,這點咱們後面會講到。
源代碼(部分)以下:this
/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. */ class ContextImpl extends Context{ //全部Application程序公用一個mPackageInfo對象 /*package*/ ActivityThread.PackageInfo mPackageInfo; @Override public Object getSystemService(String name){ ... else if (ACTIVITY_SERVICE.equals(name)) { return getActivityManager(); } else if (INPUT_METHOD_SERVICE.equals(name)) { return InputMethodManager.getInstance(this); } } @Override public void startActivity(Intent intent) { ... //開始啓動一個Activity mMainThread.getInstrumentation().execStartActivity( getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1); } }
路徑 :\frameworks\base\core\java\android\content\ContextWrapper.java
說明: 正如其名稱同樣,該類只是對Context類的一種包裝,該類的構造函數包含了一個真正的Context引用,即ContextIml
對象。 源代碼(部分)以下:.net
public class ContextWrapper extends Context { Context mBase;//該屬性指向一個ContextIml實例,通常在建立Application、Service、Activity時賦值 //建立Application、Service、Activity,會調用該方法給mBase屬性賦值 protected void attachBaseContext(Context base) { if (mBase != null) { throw new IllegalStateException("Base context already set"); } mBase = base; } @Override public void startActivity(Intent intent) { mBase.startActivity(intent); //調用mBase實例方法 } }
路徑:/frameworks/base/core/java/android/view/ContextThemeWrapper.java
說明:該類內部包含了主題(Theme)相關的接口,即android:theme屬性指定的。只有Activity須要主題,Service不須要主題,
因此Service直接繼承於ContextWrapper類。
源代碼(部分)以下:
[java] view plain copy print?rest
public class ContextThemeWrapper extends ContextWrapper { //該屬性指向一個ContextIml實例,通常在建立Application、Service、Activity時賦值 private Context mBase; //mBase賦值方式一樣有一下兩種 public ContextThemeWrapper(Context base, int themeres) { super(base); mBase = base; mThemeResource = themeres; } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); mBase = newBase; } }
Activity類 、Service類 、Application類本質上都是Context子類, 更多信息你們能夠自行參考源代碼進行理解。
熟悉了Context的繼承關係後,咱們接下來分析應用程序在什麼狀況須要建立Context對象的?應用程序建立Context實例的
狀況有以下幾種狀況:
一、建立Application 對象時, 並且整個App共一個Application對象
二、建立Service對象時
三、建立Activity對象時
所以應用程序App共有的Context數目公式爲:
總Context實例個數 = Service個數 + Activity個數 + 1(Application對應的Context實例)
每一個應用程序在第一次啓動時,都會首先建立Application對象。若是對應用程序啓動一個Activity(startActivity)流程比較
清楚的話,建立Application的時機在建立handleBindApplication()方法中,該函數位於 ActivityThread.java類中 ,以下:
//建立Application時同時建立的ContextIml實例 private final void handleBindApplication(AppBindData data){ ... ///建立Application對象 Application app = data.info.makeApplication(data.restrictedBackupMode, null); ... } public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { ... try { java.lang.ClassLoader cl = getClassLoader(); ContextImpl appContext = new ContextImpl(); //建立一個ContextImpl對象實例 appContext.init(this, null, mActivityThread); //初始化該ContextIml實例的相關屬性 ///新建一個Application對象 app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); //將該Application實例傳遞給該ContextImpl實例 } ... }
經過startActivity()或startActivityForResult()請求啓動一個Activity時,若是系統檢測須要新建一個Activity對象時,就會
回調handleLaunchActivity()方法,該方法繼而調用performLaunchActivity()方法,去建立一個Activity實例,而且回調
onCreate(),onStart()方法等, 函數都位於 ActivityThread.java類 ,以下:
//建立一個Activity實例時同時建立ContextIml實例 private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) { ... Activity a = performLaunchActivity(r, customIntent); //啓動一個Activity } private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) { ... Activity activity = null; try { //建立一個Activity對象實例 java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); } if (activity != null) { ContextImpl appContext = new ContextImpl(); //建立一個Activity實例 appContext.init(r.packageInfo, r.token, this); //初始化該ContextIml實例的相關屬性 appContext.setOuterContext(activity); //將該Activity信息傳遞給該ContextImpl實例 ... } ... }
經過startService或者bindService時,若是系統檢測到須要新建立一個Service實例,就會回調handleCreateService()方法,
完成相關數據操做。handleCreateService()函數位於 ActivityThread.java類,以下:
//建立一個Service實例時同時建立ContextIml實例 private final void handleCreateService(CreateServiceData data){ ... //建立一個Service實例 Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); } catch (Exception e) { } ... ContextImpl context = new ContextImpl(); //建立一個ContextImpl對象實例 context.init(packageInfo, null, this); //初始化該ContextIml實例的相關屬性 //得到咱們以前建立的Application對象信息 Application app = packageInfo.makeApplication(false, mInstrumentation); //將該Service信息傳遞給該ContextImpl實例 context.setOuterContext(service); ... }
另外,須要強調一點的是,經過對ContextImp的分析可知,其方法的大多數操做都是直接調用其屬性mPackageInfo(該屬性類
型爲PackageInfo)的相關方法而來。這說明ContextImp是一種輕量級類,而PackageInfo纔是真正重量級的類。而一個App裏的
全部ContextIml實例,都對應同一個packageInfo對象。
最後給你們分析利用Context獲取SharedPreferences類的使用方法,SharedPreferences類想必你們都使用過,其通常獲取方
法就是經過調用getSharedPreferences()方法去根據相關信息獲取SharedPreferences對象。具體流程以下:
1 、調用 getSharedPreferences()獲取對應的的文件,該函數實現功能以下:
//Context類靜態數據集合,以鍵值對保存了全部讀取該xml文件後所造成的數據集合 private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs = new HashMap<File, SharedPreferencesImpl>(); @Override public SharedPreferences getSharedPreferences(String name, int mode){ //其所對應的SharedPreferencesImpl對象 ,該對象已一個HashMap集合保存了咱們對該文件序列化結果 SharedPreferencesImpl sp; File f = getSharedPrefsFile(name); //該包下是否存在對應的文件,不存在就新建一個 synchronized (sSharedPrefs) { //是否已經讀取過該文件,是就直接返回該SharedPreferenc象 sp = sSharedPrefs.get(f); if (sp != null && !sp.hasFileChanged()) { //Log.i(TAG, "Returning existing prefs " + name + ": " + sp); return sp; } } //如下爲序列化該xml文件,同時將數據寫到map集合中 Map map = null; if (f.exists() && f.canRead()) { try { str = new FileInputStream(f); map = XmlUtils.readMapXml(str); str.close(); } ... } synchronized (sSharedPrefs) { if (sp != null) { //Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map); sp.replace(map); //更新數據集合 } else { sp = sSharedPrefs.get(f); if (sp == null) { //新建一個SharedPreferencesImpl對象,而且設置其相關屬性 sp = new SharedPreferencesImpl(f, mode, map); sSharedPrefs.put(f, sp); } } return sp; } }
二、SharedPreferences 不過是個接口,它定義了一些操做xml文件的方法,其真正實現類爲SharedPreferencesImpl ,該類是
ContextIml的內部類,該類以下:
//soga,這種形式咱們在分析Context ContextIml時接觸過 //SharedPreferences只是一種接口,其真正實現類是SharedPreferencesImpl類 private static final class SharedPreferencesImpl implements SharedPreferences{ private Map mMap; //保存了該文件序列化結果後的操做, 鍵值對形式 //經過key值獲取對應的value值 public String getString(String key, String defValue) { synchronized (this) { String v = (String)mMap.get(key); return v != null ? v : defValue; } } ... //得到該SharedPreferencesImpl對象對應的Edito類,對數據進行操做 public final class EditorImpl implements Editor { private final Map<String, Object> mModified = Maps.newHashMap(); //保存了對鍵值變化的集合 } }
基本上獲取SharedPreferences 對象就是這麼來的,關於Context裏的更多方法請你們參照源代碼認真學習吧。