本文原創 ,轉載必須註明出處 :http://blog.csdn.net/qinjuning
前言:本文是我讀《Android內核剖析》第7章 後形成的讀書筆記
,在此向欲瞭解Android框架的書籍推薦此書。
大家好, 今天給大家介紹下我們在應用開發中最熟悉而陌生的朋友-----Context類 ,說它熟悉,是應爲我們在開發中
時刻的在與它打交道,例如:Service、BroadcastReceiver、Activity等都會利用到Context的相關方法 ; 說它陌生,完全是
因爲我們真正的不懂Context的原理、類結構關係。一個簡單的問題是,一個應用程序App中存在多少個Context實例對象呢?
一個、兩個? 在此先賣個關子吧。讀了本文,相信您會豁然開朗的 。
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
從上可知一下三點,即:
1、它描述的是一個應用程序環境的信息,即上下文。
2、該類是一個抽象(abstract class)類,Android提供了該抽象類的具體實現類(後面我們會講到是ContextIml類)。
3、通過它我們可以獲取應用程序的資源和類,也包括一些應用級別操作,例如:啓動一個Activity,發送廣播,接受Intent
信息 等。。
於是,我們可以利用該Context對象去構建應用級別操作(application-level operations) 。
一、Context相關類的繼承關係
相關類介紹:
Context類 路徑: /frameworks/base/core/Java/android/content/Context.java
說明: 抽象類,提供了一組通用的API。
源代碼(部分)如下:
-
public abstract class Context {
-
...
-
public abstract Object getSystemService(String name);
-
public abstract void startActivity(Intent intent);
-
public abstract ComponentName startService(Intent service);
-
-
public abstract SharedPreferences getSharedPreferences(String name,int mode);
-
...
-
}
ContextIml.java類 路徑 :/frameworks/base/core/java/android/app/ContextImpl.java
說明:該Context類的實現類爲ContextIml,該類實現了Context類的功能。請注意,該函數的大部分功能都是直接調用
其屬性mPackageInfo去完成,這點我們後面會講到。
源代碼(部分)如下:
-
-
-
-
-
class ContextImpl extends Context{
-
-
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) {
-
...
-
-
mMainThread.getInstrumentation().execStartActivity(
-
getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
-
}
-
}
ContextWrapper類 路徑 :\frameworks\base\core\java\android\content\ContextWrapper.java
說明: 正如其名稱一樣,該類只是對Context類的一種包裝,該類的構造函數包含了一個真正的Context引用,即ContextIml
對象。 源代碼(部分)如下:
-
public class ContextWrapper extends Context {
-
Context 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);
-
}
-
}
ContextThemeWrapper類 路徑:/frameworks/base/core/java/android/view/ContextThemeWrapper.java
說明:該類內部包含了主題(Theme)相關的接口,即android:theme屬性指定的。只有Activity需要主題,Service不需要主題,
所以Service直接繼承於ContextWrapper類。
源代碼(部分)如下:
-
public class ContextThemeWrapper extends ContextWrapper {
-
-
-
private Context 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對象的?應用程序創建Context實例的
情況有如下幾種情況:
1、創建Application 對象時, 而且整個App共一個Application對象
2、創建Service對象時
3、創建Activity對象時
因此應用程序App共有的Context數目公式爲:
總Context實例個數 = Service個數 + Activity個數 + 1(Application對應的Context實例)
具體創建Context的時機
1、創建Application對象的時機
每個應用程序在第一次啓動時,都會首先創建Application對象。如果對應用程序啓動一個Activity(startActivity)流程比較
清楚的話,創建Application的時機在創建handleBindApplication()方法中,該函數位於 ActivityThread.java類中 ,如下:
-
-
private final void handleBindApplication(AppBindData data){
-
...
-
-
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();
-
appContext.init(this, null, mActivityThread);
-
-
app = mActivityThread.mInstrumentation.newApplication(
-
cl, appClass, appContext);
-
appContext.setOuterContext(app);
-
}
-
...
-
}
2、創建Activity對象的時機
通過startActivity()或startActivityForResult()請求啓動一個Activity時,如果系統檢測需要新建一個Activity對象時,就會
回調handleLaunchActivity()方法,該方法繼而調用performLaunchActivity()方法,去創建一個Activity實例,並且回調
onCreate(),onStart()方法等, 函數都位於 ActivityThread.java類 ,如下:
-
-
private final void handleLaunchActivity(ActivityRecord r, Intent customIntent) {
-
...
-
Activity a = performLaunchActivity(r, customIntent);
-
}
-
private final Activity performLaunchActivity(ActivityRecord r, Intent customIntent) {
-
...
-
Activity activity = null;
-
try {
-
-
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
-
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
-
}
-
if (activity != null) {
-
ContextImpl appContext = new ContextImpl();
-
appContext.init(r.packageInfo, r.token, this);
-
appContext.setOuterContext(activity);
-
...
-
}
-
...
-
}
3、創建Service對象的時機
通過startService或者bindService時,如果系統檢測到需要新創建一個Service實例,就會回調handleCreateService()方法,
完成相關數據操作。handleCreateService()函數位於 ActivityThread.java類,如下:
-
-
private final void handleCreateService(CreateServiceData data){
-
...
-
-
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();
-
context.init(packageInfo, null, this);
-
-
Application app = packageInfo.makeApplication(false, mInstrumentation);
-
-
context.setOuterContext(service);
-
...
-
}
另外,需要強調一點的是,通過對ContextImp的分析可知,其方法的大多數操作都是直接調用其屬性mPackageInfo(該屬性類
型爲PackageInfo)的相關方法而來。這說明ContextImp是一種輕量級類,而PackageInfo纔是真正重量級的類。而一個App裏的
所有ContextIml實例,都對應同一個packageInfo對象。
最後給大家分析利用Context獲取SharedPreferences類的使用方法,SharedPreferences類想必大家都使用過,其一般獲取方
法就是通過調用getSharedPreferences()方法去根據相關信息獲取SharedPreferences對象。具體流程如下:
1 、調用 getSharedPreferences()獲取對應的的文件,該函數實現功能如下:
-
-
private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
-
new HashMap<File, SharedPreferencesImpl>();
-
-
@Override
-
public SharedPreferences getSharedPreferences(String name, int mode){
-
-
SharedPreferencesImpl sp;
-
File f = getSharedPrefsFile(name);
-
synchronized (sSharedPrefs) {
-
sp = sSharedPrefs.get(f);
-
if (sp != null && !sp.hasFileChanged()) {
-
-
return sp;
-
}
-
}
-
-
Map map = null;
-
if (f.exists() && f.canRead()) {
-
try {
-
str = new FileInputStream(f);
-
map = XmlUtils.readMapXml(str);
-
str.close();
-
}
-
...
-
}
-
-
synchronized (sSharedPrefs) {
-
if (sp != null) {
-
-
sp.replace(map);
-
} else {
-
sp = sSharedPrefs.get(f);
-
if (sp == null) {
-
-
sp = new SharedPreferencesImpl(f, mode, map);
-
sSharedPrefs.put(f, sp);
-
}
-
}
-
return sp;
-
}
-
}
2、 SharedPreferences 不過是個接口,它定義了一些操作xml文件的方法,其真正實現類爲SharedPreferencesImpl ,該類是
ContextIml的內部類,該類如下:
-
-
-
private static final class SharedPreferencesImpl implements SharedPreferences{
-
private Map mMap;
-
-
-
public String getString(String key, String defValue) {
-
synchronized (this) {
-
String v = (String)mMap.get(key);
-
return v != null ? v : defValue;
-
}
-
}
-
...
-
-
public final class EditorImpl implements Editor {
-
private final Map<String, Object> mModified = Maps.newHashMap();
-
}
-
}
基本上獲取SharedPreferences 對象就是這麼來的,關於Context裏的更多方法請大家參照源代碼認真學習吧。