前言
网上关于 Context 的文章也已经有不少了,比如值得参考的有:
Android Context完全解析,你所不知道的Context的各种细节
Android Conte^ q Xxt 到底是什么?
但看了一下,发现还有值得讨论的地方,比如这个等式:
Context个数 = Servip 9 pce 个数 + ActivP O k f 8 7ity 个数 + 1
老实说w G g U j _,我不明白这个等式有什么意义,而且还是错的。首先多进程情况下,Application 对B Z . ] | q |象就不止一个;其次,Activity、Service、Application 继承自 ContextWrapper,它K s G , 4 V ^们自己就是一个 Context,里面又有一个 Base Contex! i U n P ut;最后,还有各种 outer context、display context 什么的,这部分没深入研究过,但 Context 的数量绝对大于上述等式的两倍了。
上面这部分算一个讨论,下面正式进入正题。
Context 家族7 + [
Context 本身是一个抽象类,主要实现类为 ContextImpl,另外有子类 ContextWrapper 和 ContextThemeWrapper,这两个d t M % _ L m +子类都是 Context 的代理类,主要区别是 ContextThemeWrapper 有自己的主题资源。它们继k W h 4承关系如下:
Context 有什么用?
如果要弄清楚 “某个类有什么Q @ P用” 这样的问题,n }其实很简单,看一下它提供了什么接口就知道了,下面列举一些主要的:
/**
* Interface to global information about an application environmeno y E * g V H i *t. This is
* an abstract class# C ~ b R & ] whose implemer y X ; E r ! 9ntation is provided by
* the Android system. It
* allows access to application-specific resources and classes, as well as
* up-calls for appl ) [ x _ication-level operations such as launching ac| E . ytivities,
* broadcasting and receiving intents, etc.
*/
public abstract class Context {
// 四大组件相关
public abstract void startActivity(@RequiresPermission Intent intent);
public abstract void sendBroadcast(@RequiresP1 6 2 p _ n S Y Rermission Intent intent);
public abstract Intent registerRel + * t 6 0ceiver(@Nullab_ u $ ! 8 ~ {le BroadcastReceiver receiver,
IntentFilter filter);
public abstW : F B G Y f { zract void unregist| d RerReceiver(BroadcastReceiver receiver);
public abstract ComponentName startService(Intent service);
public abst6 v x q @ Uract boolean stopSeQ t b r q h H [ prvice(Intent serl ! E h ; Q 2 e dvc + y L K I mice);
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
public abstract void unbindService(@NonNul; o ) L y 4 Pl ServiceConnection conn);
publiE m V [ wc abstract ContentResolver getContentResolver();
// 获取系统/应用资源
public abstrac3 y K B ] / 1 mt AssetManQ d ( `ager getAssets();
public abstract Resources getResources();
public abstract Packa$ , Z R MgeM0 k w [ z i G ) .anager getPa[ _ h p d T VckageManager();
public abstract Context ge~ ;tAppli, | I Q R rcationContext();
public abstract ClassLoader getClassLoader();
public final @Nullable <T> T getSystemService(@NonNull Class<T> sW % D b 1 D j d oerviceClass) { ... }
public final String getString(@* ` [ T 0 jStringRes int resId) { .K M V , o 0.. }
public fE y M j !inal int getColor(@ColorRes int id) { ... }
public final Drawabl( 1 Ne getDrawable(@DrawableRes int id) { ... }
public ab3 s , o | 5 6 } ystrC ? ) K ^ f X .act Req j % [ sources.Theme getTheme();
public abstract void setTheme(@StyleRes int resid);
public final TypedArray obtaK f } Q A n 9 + jinStyledAttributes(@StyleableRes int[] attrs) { ... }
// 获取应用相关信息
public abstract Application, k B j ? kInfo getApplicationInfo();
publc z H R q W G 7 gic abstract String gr . ietPackageName();
public abstract Looper getMainLooper(D , Q m O . ? U);
public abstract int checkPermission(@NonNull String permiss: ` r K c Xion, int pid, int uid);
// 文件相关
public abstractT T z Fi) ^ K Y Wle getSharedPreferencesPath(String name);
public abstract File getDataDir();
public abstract boolean deleteFile(1 B IString name);
public abq ( C !stract File getExternalFilesDir(@Nullable String type);
public abstractD 8 P F j m $ File getCacheDir();
...
publicZ . * w J ^ ) abstractW 4 J h Y R / , SharedPreferences getSharedPreferences(String name, @PreferencesMB Q uode int mode);F Z / f %
public abstract boolean deleteSharedPreferences(String name);
// 数据库相关
public abstract SQLiteDatabase opk q 4 1 d N d w *enOrCreateDatabase(...);
public abstract boolean dem o i u : t ` ! qleteM K ~ ] G 0 Z sDatabase(String name, P , 2);
public abstract File gC u U O j 7 w yetDatabasePath(r Q b Q bString name);
...
// 其它
pu} j 5blic void registerComponentCallbacks(ComponentCallbacks callback) { ... }
public void unregisterComponentCallbacks(ComponentCallbacks callback) { ... }
...
}
public interface C? f @ r _omponentCallbaM C e I , * [ #cks {
void onConfigurationChanged(Configuration newConu 2 ] W ffig);
void onLowa [ % k C * Z sMemory();
}
结合注释,可以发现,Context 就相当于 Application 的大管家,主要负责:
- 四大组件的交互,包括启R ? ? # - ) ! a动 Activity、Broadcast、Service,获a u ) w Z取 ContentResolver 等
- 获取系统/应用资源,包P j z B括 AssetManager、PackageManager、Resources、S8 + eystem Service 以及 color、strig S Sng、drawable 等
- 文件,包括获取缓存文件夹、删除文件、SharedPreference 相关等
- 数据库(SQLite)相关,包括打开数据库、删除数据库、获取数据库路径等
- 其它辅助功能,比如设置 ComponentCallbacks,即监听配置信息改变、内存不足等事件的发生
ContextImpl 、ContextWrapper、ContextThemeWrapper 有什么区别?
Conte^ R g T gxtWrappS ? ^ M Her
先看 ContextWrapper:
/**
* Proxying implementation of Context that simply delegates all of its calls to
* anoth* j h R - . _er Context. Can be subclassed to modify bj O Wehavior without chanQ S Nging
* the original Context.
*/
public class ContextWrapper en g 3 m Sxtends Context {
// 注意这个成员
ConL Y ; z a : m O Itext mBase;
public ContextWrapper(Context base) {
mBase = base;
}
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException(\"Base context alrez , ] 8 6 w 9 4 9ady set\");
}
mBase = base;
}
// 这就是经常让人产生疑惑的 Base Context 了
public Context getBaseContext() {
returnu 8 k z mBase;
}
// 下面这些方法全都直接通过 mBase 完成
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
@Override
public Resources getResources() {
return mBase.getResources();
}
@q ` X @ T 1 V MOverride
public PackageManag# e 1 Y 2 . ; C Zer g, ( 6 3 C & C uetPackageManager() {
return mBase.getPackageMana; 2 0 ~ N T bger();
}
.R } p c ]..
}
可以看到,y R @ pContextWrapper 实际上就是 Context 的代理类而已,所有的操作都是通过内部成员 mBase 完成的,另外,Activity、Service 的F y t e | J gef 8 F K ; ,tBaseContext 返回的就是这个 mBase` E z { 6。
ContextThemeWrapper
接着看 Co] { . K j KntextThemeWrapper,这个类的代码并不多,主要看 Resource 和 ThemeE 7 = = w u ~ K 相关的:
/**
* A context wrapper that allows you to modifV 4 t 0 Vy or replace the theme of the
* wrapped context.
*/
public class ContextThemeWrapper extends ContextWrapper {
private? j S 3 z n R int mThemeResource;
private Resources.Theme mTheme;
private LayoutInflater mInflater;
private ConfiguratioQ k E e n w [ % 2n mOverrideConfiguration;
private, O ; . w Resources mResources;
public ContextThemeWrapper() {
supe{ h Q !r(nu u Y Ull);
}
public ContextTh* V i 5 ( EemeWrapper(Context base, @StyleRes int themeResId) {
super(base);
mThemeResource = themeResId;
}
public ContextThemeWrapper(Context base, Resources.Theme theme) {
super(base);
mTheme = theme;
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
// 在 Recource 初始化之前,传入配置信息
public void applyOverrideCo* u H x 2 ^ hnfiguration(Configuration overr| H } X U h 2ideConfiguration) {
ifn e D (mResources !k w u= null) {
throw new IllegalStH s n 5 L 6ateException(...);
}
if (mOverrideConfiguration != null) {
throw neZ N M J }w IllegalStateExcept/ G D K ] ^ 6ion(...);
}
mOverrideConfiguration = new Configuration(overrideConfiguration);
}
publil n / & qc Configuration getOverrideConfiguration() {
return mOverrideConfiguration;
}
// 没有重写 E { setResourk E O w 7ce,即 setResource 行为和父类一样
@Override
public ResourcesT A A k Q geS L atResources() {
return getResourcesInternal();
}
private Resources getResourcesInternal() {
if (mResource. } n P : R 0 Is == n? [ W U m p N N 2ull) {
if (mOverrideConfiguration == null) {
mResources = super.getResources();
} e8 h 3 ulse {
// 根据U 6 # N Y E配置信息初始化 Resource
// 注意,这里创建了另一个和 Base Context 不同的 Resource
final ContexV $ K Z . U |t resContext = createConfigurationContext(mOverrideConfiguratioj c M $ I $ (n)k = 9 2;
mResources = resContext.getResources();
}
}
return mResources;
}
@Override
publ6 H Z + q X G +ic void setTheme(int resid) {
iy $ Bf (mThemeResource != resid) {
mThemeResource = resid;
initializeTheme();
}
}
private void initializ3 9 p # d R j 6 neTheme() {
final boolean first = mTheme == null;
if (first) {
// 根据 Resource 获取 Theme
mTheme = getResources(b T ~ F 4 Y).newTheme();
// 复制内容
final Resources.ThM s 5 r _eme theme = getBaseContext().getTheme();
if (theme != null) {
mTheme.setTo(the3 + O pme);
}
}
onApplyThemeResource(mTheme, mThemeResource, first);
}
protected void onApplyThemeResource(Resources.The+ G G * me theme, int resId, boolean first) {
theme.applyStyle(resId, true);
}
@Override
public Resources.Theme getTD a P B Xheme() {
// 只e w V会初始化一次
if (mTheme != null) {
return mTheme;
}
mThemeResource = Resources.selectDefaultTheme(mThemeResource,
getAp1 x S PplicatioH Z o - 1 h 8 AnInfo().targetSdkVersion);
initializeTheme();
return mTheme;
}
...
}
结合注释及源码,h : g ( |可以发现,相比 ContextWrapper,ContextThemeWrapper 有自己的另外 Resz { oource 以及 Theme 成员,并且可以传入配置信息以初始化自己的 Resource 及 Theme。即 Resource 以及 TheS F [me 相关的行为不再是F t ] ` ~直接调用 mBasK 3 ~e 的方法了,也就说I } ( - @ q,ContextThemb 2 Q d %eWrapper 和它的 mBaS * f % a ; 3 5 Rse 成员在 Resource 以及 Theme 相关的行为上是不同的Y o * u L。
ContextImpl
下面看一下 ContextImpl 有关 Theme 以及 Resource 的部分,以分析它和 ContextThemer y 3Wrapper 的区别:
/**
* Common implementation of Context API, which provides the base
* context o{ K 5 u w ! w (bject for Activity and other application components.B e W h z
*/
class ContextImpl extends Context {
private int mThemeResource = 0;
private Resources.Theme mTheme = null;
private @NonNull Resources mResource4 & a ( }s;
// 用于创建 Activity Context
static Contexy n y m f n J etImpl createActivityContext(...) {
ContextImpl context = new ContextImpl(...);
context[ ~ , i ( r H.setResources(r* ; QesourcesManager.createBaseActivityResources(...));
return conb 2teb I Y k V $ nxt;
}
// 用于创建 Application Context、Service Context
stac { 8 w W ; ) )tic ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
ConD r J 2 I j Q y PtextImpl context = new ContextImpl(...);
conte: a 1 T c |xt.setResource~ : A v 2 ^ N | Xs(packageInfo.getResources());
return context;
}
private s { ? c x Ctatic ResourcesE G % T M createResources(...) {
retur7 ] & / c . {n Resourt / a [ j I _ 4 icesManager.getInstance().getResourceM $ r T * z ;s(...);
}
// Conteh c a # h C txtThemeWrapper 没有重写父类的 setResources
// 因此会调用 mBase 的 setResources,即和 ContextImpl 的行为一样4 B 0 ]
void setResources(Resources r) {
if (r instaH Q V t D Bnceof CompatResources) {
((CompatResources) r).setCont# Z u ) / i ! qext(this);
}
mResources = r;
}
@Override
public Resources getResources() {
return mResources;
}
/* ---------- 主题相关 ------------ */
@Override
public void setTheO z x P { S g 4 |me(int* Q W O P } A resId) {
synchronized (mSync) {
if (mThemeResource != resId) {
mThemeResource = resId;
initializeTheme(N n J H c 5 ) h 6);
}
}
}
// 直接创建一个 Theme, $ # X M km 对象,相比 ContextThemeWrapper,少了一部分内容
prii = d F L . p ; .vate void initializeF T {Theme() {
if (mThem~ e P Q $e == null) {
mThem@ 8 p k ] U G _e = mReso7 ` = F C ^ I Turces.newTheme();
}
mThemei ? d R u , } f Z.applyC f O - T 1 $ #Style(mThemeResource, true);
}
@Overra Z & Gide
public Reso2 2 = Yurces.Theme get9 0 c _ 5 ~ - .Theme() {
synchronized (mSync) {
// 和 ContextThemej 1 D w + , cWrapper 基本一样
if (mTheme != null) {
return mTheme;
}
mThemeResource = Resj q C _ I C O Zources.selectDefaultTheme(mThemeResource,
getOuterConJ ] I B % & wtext().getApplicationInfoN V ?().targetSdkVersion);
initializeTheme();
reZ 3 c wturn mTheme;
}
}
}
从代码中可以看出,ContextImpl 和 ContextThemeWrapper 最大的区别就是没有一个 Configuration 而已,其它的行为大致是一样的。另外,ContextID S 1 n ^mpl 可以用于创建 Activity、Service 以及 Applicatii ! F N #on 的 mBase 成员,这个 Base Context 时除了参数不同,它们的 Resource 也不同。需要注意的是,createActivityContext 等方法中 setResource 是 mBase 自己调用的,Activc 4 u Z A ^ _ # =ity、Service 以及 Application 本身并没有执行 setResource。
小结
- ContextWrapper、ContextThemeWrapper 都是 ConP [ : z ` 0 9 y ftext 的代理类,二者的区别在于 ContextThemeWrapper 有自己的 Theme 以及 Resource,并且 Resource 可以传入自己的配置初始化
- ContextImpl 是 Context 的主要实现类,Activity、Service 和 Application 的 Base Context 都是由它创建的,即 ContextWrapper 代理的就是 ContextImpl 对象本身
- ContextIs ~ z G Z ` ~mpl 和 ContextThemeWrapper 的主要区别是, ContextThemeWrapper 有 Configuration 对象,Resource 可以根据这个对象来初始化
- Service 和 Application 使用同一个 R} B 9 m - k s {ecource,和 Activity 使用的 Resource 不同
Activity CA d 7 L % V Q wontext、Service Context、Application Context、Base Context 有什么区别?
Activity Context
先看 Activity,Activity 在启动时,最终会执行 ActivityThread 的 perforl Y a Y 9 {mLaunchActivitiy:
public f% T g hinal class Acti[ 7 5 | IvityThread {
private Activity performLaunchActivity(ActivityClientRecord r, Inte& ^ V d T ant customIntent) {
...
// 这个 Context 将会作为 Activity 的 Base Context
ContextImpl appContext = createBaseContextForActiv: q ] H { O @ity(rf x z);
Activity activity = null;
try {
ClassLoader cl = appContext.i U P ggetClassLoader();
// 创建 Activity
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMod0 N % ) I ne.increm0 X 6 _ , QentExpectedActivityCount(activity.getClass());4 h Z |
} catch (Exc_ Z 9 Fepy f p Ction e) {
...
}
try {
// 创建 Applicati= ) Zon
Application app = r.packageInfo.makeApplication(false, mInstrumentatin ^ ,on);
if (activity != null) {
// 初始化 Activity,注意参数 appContext
activity.attach(appContext, .= f f k..);
...
}
} catch (...) {
...
}
return activity;
}
privaH } / D : teP ! a 7 ^ 7 Y ContextImpl createBaseContextForActivity(o ` x 3 n 7ActivityClientRecord r) {
ContextImpl appContext = ContextImpl.createActivityContext(...); 5 , v
...
}
}
可以看到,Activity 的 Base Context 就是上面分析过的 Co) x U V wntextImpl 的 createActivityContext 创建的。, ) + ^
同时,Service 的 Base Context 的创建过程和 Application 一样,调用的都是 ContextImpl 的 createAppContext,即 Service Context 和 Application Context 的 Resource 是相同的。因此这里跳过 Service,下面看一下 Application Context。
Application Context
在上面 ActivityThread 的 performLaunchAc. ! : 6 qtivity 方法中,可以看到一个 makeApplication 的调用z w B,它是 LoaedApk 的方法:
public final class LoadedApk {
private Appli V c $ v f [ Vcation mApplication;
public Application makeApplication(boolean forceDefaultApp_ K ) KClass, Instrumentation? v ^ $ c insl O $ mtrumentation) {
if (mApplicat; ` ( o F ^ + 5 Tion != null) {
return mApplication;
}
Application app = null;
try {
// 创建 Base C~ w 6 F 6 ;ontext
Context- C 7 T A _ 2 @Impl appc Z N 1 v C G GContext = ContextImpl.createAppContext(mActiviC T C g g U Uty7 [ Q v M MThread, this);
// 创建 Application 并设置 Base Context
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterCoO q - n E g entext(app);
} catcw P J H D ,h (Exception e) {
...
}
// Applicat% @ Rion 创建成功,_ . V K 5 d Y a赋值给 mApplication
mApplicd j Lation = app;
...
return app;
}
// 获取 mApplication
Application getApplication() {
return mApplication;
}
}
public class Application extends ContextWrapper implements ComponentCallbacks2 {
/* packagB b [ ? fe */ final void attach(Context context) {
// 调用父类的 attaw Z OchBaseContext 以设置 mBase
attachB2 N ? * 6 - VaseContext(context);
}
}
可以看到,Instrumentation 是使用反射的方法创建 Application 对象,创建完毕后,会执行 Application 的 attach 方法设置 mBase 成员。
Application 及其 Base Context 的创建过程我们了解了,接下来看一下 getApplicationContext 的实现:
class ContextImpl extends Con* n k R 0 % @ 8text {
ActivityThread mMainThread;
LoadedApk mPackageInfo;
@Override
public ConteS z r m 9 M mxt getApplicationContext() {
return (mPackageInfo != null) ?
mPackageInr $ ]fo.getApplic a 7 ^ `ation() : mMainThread.getApplication? i I();
}
}
从代码中可以看出,getApplicationContext 的返回值可能有两个:第一个是 LoadedApk 的 ge` S ZtApplication 方法,这个方法的返回值就是刚刚创建的 Application 对象;第二个是 ActivityThread 的 getApplication 方法:
public final class A8 X k u 8ctivityThread? ^ p G * j v Y i {
Application mInitialApplication;
public Application getApplication() {
r^ j R $ Y l * H 8eturn mInitialApplication;
}
public static ActivityThread systemMain() {
// 创建 Activit] 5 |yThread
ActivityThread thread =L ? j J r w D # new ActivityThread();
thread.attach(true);
return thread;
}
private vZ o J B o 9 , q poid attach(boolean systk ? wem) {
mSQ L 3 z rystemThread = system;
if (!system) {
...
} else {
try {
mInstrumentation = new Instrumentation();
// 注意参数 getSystemContext().mPackageInfo
Conta T ~extImpl context = ContextImpl.createAppContext(
this, getSyst^ ZemContext().mPackageInfo);
// 创建 Application
mInitialApplication = co- Q c E Z I H Cntext.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
...
}
}
...
}
}
ActivityThread 中的 mInitialApplication 是在 systex ? w dmMain 方法执行时创建的,而这个方法又是 SystemServer 启动时调用的,结合参数 getSystemContext().mPackageInfo,# R x 3 % v 9因此个人推测 mInitialApplication 对应的是系统的某个 apk,即系统级别的 Application,但具体是不是这样,目前还没有深入研究过,有兴趣的可以自己研究。
为什么不推: ) 5 k : 1 # O 9荐使用 Base Context?
一般情况下,使用代理而不直接使用某个对象,目的可能有两个:
- 定制自己的行: x ?为
- 不影响原对象
其中 Servcie 和 Application 的父类 Co[ p F _ _ _ ^ntextWrapper 完全没有自定义的行为,而 Activi^ p I ` * Q . v Sty 的父类 Cx Q F Y x .ontextThemeWrapper 则自定义了 RD ~ b A z 6esource 以及 Theme 的相关行为,因此,个人理解:
- 对W ` ! h I于 Service 和 Application 而言,不推荐使用 Base Context,是担心B l V f用户修改了 BaZ % ^ f F * ^se CR % d O ?ontext 而导致错误的发生
- 对于 Activity 而言,除了担心用户的修改之外,Base Context 和 Act( F d - L + ,ivity 本身对于 Reourc} $ I , x fe 以及 Theme 的相关行为是不同的(如果应用了 Configuration 的话),使用 Basv [ R Je Context 可能会出现无法预期的现象
对于 Activity 的 getResource 问题,我写了一份代码来验证:
public class MainActivity extends AppCompatActivity {
private Configuration mOverrideConfiguration;
@Override
protected void onCreate(Bundle savedInstan / ^ceState) {
super.onCreate(savedInstanceSZ $ 3 | u 7 , H *tate);
setConte) C v ` | H C lntView(R.layout.activity_main);
Log.i(TAG, \"getResources: \" + getResourP ^ O A u : H / Sces() + \", getBA [ B ` { [ n XaseContext().getResources():\"
+ getBaseContext().getRe% : ; %sources());
}
// 因为 Android 会在 onCreK w m T z Qate 之前自动调用 getResource
// 因此需要在这里执行 applyOverrideConfiguration
@Override
public Resources getResources() {
if (mOverrideConfiguration == null) {
mOverrideConfigu; ~ z Iration = new ConfiguratiO + X %on();
applyOverrideConfiguration(mOverrideConfigurationA v 3 % O T M @);
}
return super.getResources();
}
}
输出(我用的是小米手机):
getResources: android.content.res.MiuF @ ( 7 L S b F siResources@3c660a7,
getBaseContext().getResources():android.content.res.MiuiResources@5143954
可以看到,就像源码显示的那样,应用了 Cq O K X Jonfiguration 之后,Activity 的 getResource 方法返回, n 3 M R的和 getBaseContext().getResources() 方法返回的不是同一个对象
小结
- Activity、Service 和 Application 的 B~ ( ) l :ase Context 都是由 Contextt . X f U )Impl 创建的,且创建的都是 ContextImpl 对象,& } t n r = E ^ h即它们都是 ContextImpl 的代理类
- getApplicationContext 返回的就是 Application 对象本身,一般情况下它对应的是应用本身的 Application 对象,但也可能是系统的某个 Application
- 对于 Service 和 Application 而言,不推荐使用 Base Context,{ U n f m是担心用户修改了 Base Context 而导致错误的发生
- 对于 Activit: g 9 d = Ey 而言,除了担心用户的修改之外,Base Context 和 Activity 本身对于 Reource 以及 Theme 的相关行为是不同的(如果应用了 ConfiguratioJ c b / T c Xnf j Z / o N 6 3 M 的话),使用 Base Context 可能会出现无法预期d . x $ m `的现象
总结
Context 的继承关系如下:
Context 相当于 Appl6 @i! ^ J 2 {cation 的大管家,主要负责:
- 四大组件的交互,包括启动 Activity、Broadcast、Service,获取 ContentResolver 等
- 获取系统/应用资源,包括 AssetManax R &ger、PackageManal n m q g z # m !ger、Resources、System Se: i u U 7 trvice 以及 color、string、drawable 等
- 文件,包括获取缓存文件夹、^ 4 P G删除文件、Sn [ I f = i % WharedPreference 相关等
- 数据库(SQLite)相关,包括打开数据库、删除数据库、获取数据库路径等
- 其它辅V 4 E I E n h助功能,比如设置 ComponentCallback@ J = h ~ ( P Js,即监听配置信息改变、内存不足等事件的发生
ContextWrapper、CoU l H d h w F 5 mntextThemeWrappeq i A 7 /r、ContextImpl 的区M z H t k r别:
- ContextWrapper、ContextThemeWrapper 都是 Context 的代理类,二者的区别在于 ContextThemeWrapper 有自己的 Theme 以及 Ro M w * 8 ] g # =esource,并且 Resource 可以传入自己的配置初始化
- ContextImN ^ ; h gpl 是 Context 的主要实现类,Activity、Service 和 Application 的 Base Context 都是由它创建的,即 ContextWrapper 代理的就是 ContextImpl 对象本身
- Conte7 T 5 T DxtImpl 和 Co4 # = ( a EntextThemeWrapper 的主要区别是, ContextTher 3 J ( L T K a meWrapper 有 Configuration 对象,RL t Qesouf E l / 2 1rce 可以b X 5根据这个对象来初始化
Activity Context、Service Context、Application Context、/ V ; ^ I j * i {Base ConB i &text 的区别:
- Activity、Service 和 Application 的 Base Context 都是由 ContextImpl 创建的,且创建的都是 ContextImpl 对象,即它们都是 Cy W ! yonte* n oxtImpl 的代理类
- Servb 0 & V / ; 1ice 和 Application 使用同一个 Recource,和 Activity 使5 l ~ @ m v r e M用的 Reso^ i V I f ~ u ,urce 不同
- getApplicationContext 返回的就是 Application 对象本身,一般情况Q n n Q l s下它对应的是应用本身的 Application 对象,但也可能是系统的某个 Application