Context
1.context是一个抽象类,定义了一些枚举和获取资源方法
继承关系如下:
Context --> ContextImpl
| |
v |
ContextWrapper<-----
|
-----------------------------------------------
| | |
v v v
Application Service ContextThemeWrapper
|
v
Activity
ContextThemeWrapper与ContextWrapper的区别:
在于为Activity加载定义的Theme中的样式,Application和Service都不需要界面上的展示
2.如何保证访问资源的唯一性?
我们直接来看ContextImpl中的源码
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {
mOuterContext = this;
......
mPackageInfo = packageInfo;
mResourcesManager = ResourcesManager.getInstance();
.....
Resources resources = packageInfo.getResources(mainThread);
if (resources != null) {
if (displayId != Display.DEFAULT_DISPLAY
|| overrideConfiguration != null
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
if (container != null) {
// This is a nested Context, so it can't be a base Activity context.
// Just create a regular Resources object associated with the Activity.
resources = mResourcesManager.getResources(
activityToken,
packageInfo.getResDir(),
packageInfo.getSplitResDirs(),
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
packageInfo.getClassLoader());
} else {
// This is not a nested Context, so it must be the root Activity context.
// All other nested Contexts will inherit the configuration set here.
resources = mResourcesManager.createBaseActivityResources(
activityToken,
packageInfo.getResDir(),
packageInfo.getSplitResDirs(),
packageInfo.getOverlayDirs(),
packageInfo.getApplicationInfo().sharedLibraryFiles,
displayId,
overrideConfiguration,
compatInfo,
packageInfo.getClassLoader());
}
}
}
mResources = resources;
.....
}
首先一个应用只有唯一的mPackageInfo这个能够保证,mResourcesManager是取的一个单例。
3.单例模式的正确运用
在一个需要使用context来初始化的单例中,我们需要在获取单例是传入context。
我们已有的只是告诉我们,持有activity的context在activity销毁之后会造成内存泄漏,且单例一般如工具类都需要做到与应用的生命周期相同,所以我们可以直接使用Application的context来进行初始化。
public class Singleton {
private static volatile Singleton instance = null;
private Context mContext;
public Singleton(Context context) {
this.mContext = context;
}
public Singleton getInstance(Context context) {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(context.getApplicationContext());
}
}
}
return instance;
}
}
从代码中可以看到,用context的getApplicationContext()来保证我们使用的只会是Application的Context。
4.如果用Application的context是否可以启动一个activity,会出现什么异常情况?
我们直接尝试利用Application的Context来启动Activity,跟网上说的会报异常或者创建在新的任务中的结论不符啊,有大神看到麻烦指点下。
--!
5.如果用Application的context是否可以inflateLayout,会出现什么异常情况?
由于Activity是继承于ContextThemeWrapper,所以用Activity的Context创建的View或者Dialog等会带有自定义的Theme,若使用Service或者Application的Context则会使用系统默认的样式。
6.避免将context用来创建static变量
网上的一个例子:
private static Drawable sDrawable;
sDrawable = context.getDrawable(R.mipmap.ic_launcher);
将一个静态变量drawable用context(假设为Activity的context)进行初始化,由于被静态变量所持有,会导致内存泄漏问题。
tips
不要让比context生命周期长的对象持有该context,如在Activity中使用presenter的问题,必须要进行相应的解决。
参考
Android Context 熟悉还是陌生?
Android基础之Context
Android应用Context详解及源码解析