http://www.androidchina.net/3853.html
http://www.jianshu.com/p/f24707874b04
1,Context介绍
/**
* 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.
*/
public abstract class Context {
......................
}
通过注释得知:
1、它描述的是一个应用程序环境的信息,即上下文。
2、该类是一个抽象(abstract class)类,Android提供了该抽象类的具体实现类(ContextIml类)。
3、通过它我们可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent信息 等。
2,Context 之间的关系
先介绍一下context 类的继承关系,之后的讲解可以结合这张图来分析:
摘自:http://blog.csdn.net/yanbober/article/details/45967639
ContextImpl:该类实现了Context类的所有功能。
/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
private Context mOuterContext;
......
}
ContextWrapper
/**
* 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;
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.
*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
......
}
ContextThemeWrapper:
/**
* A ContextWrapper that allows you to modify the theme from what is in the
* wrapped context.
*/
public class ContextThemeWrapper extends ContextWrapper {
......
}
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback {
......
}
Service
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
......
}
Application
public class Application extends ContextWrapper implements ComponentCallbacks2 {
......
}
先来说,这些之后都会结合源码详细讲解(只是为了自己方便才先写出来)
- context 是一个抽象类,提供类很多抽象的方法
- contextImpl 是context的实现类 继承context ,主要对抽象方法具体化,所有的context的具体操作都在这里。
- contextWrapper 是对context的包装类 继承context,
- contextThemeWrapper 是有主题的context,因为activity有主题(就是我们在Manifest里面配的),所以activity extendscontextThemeWrapper
- contextWrapper 有一个特别重要的变量 Context mBase,一般在启动activity、service、application 的时候通过先attachBaseContext ,把new 出来contextImpl赋值给mBase 之后,在通过回调 执行 各自的生命周期。
/**
* 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.
*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
- 源码中是将 contextImpl--->base,也就是在contextWrapper中,通过base 来操作 contextImpl
- 最终的操作都是在 contextImpl 实现的
3,Context在ActivityThread中实例化过程源码分析
Context的实现是ContextImpl,Activity与Application和Service的创建都是在ActivityThread中完成的,重点分析各context的创建过程。
3.1Activity中ContextImpl实例化源码分析
通过startActivity启动一个新的Activity时系统会回调ActivityThread的handleLaunchActivity()方法,内部在调用performLaunchActivity创建activity,然后回调onCreate等方法,所以activity的contextImpl在performLaunchActivity中
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
//已经创建好新的activity实例
if (activity != null) {
//创建一个Context对象
Context appContext = createBaseContextForActivity(r, activity);
......
//将上面创建的appContext传入到activity的attach方法
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor);
......
}
......
return activity;
}
createBaseContextForActivity()创建context,再通过attach,把appContext传入activity中。
private Context createBaseContextForActivity(ActivityClientRecord r,
final Activity activity) {
//实质就是new一个ContextImpl对象,调运ContextImpl的有参构造初始化一些参数
ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);
//特别特别留意这里!!!
//ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Activity对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Activity)。
appContext.setOuterContext(activity);
//创建返回值并且赋值
Context baseContext = appContext;
......
//返回ContextImpl对象
return baseContext;
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
//特别特别留意这里!!!
//与上面createBaseContextForActivity方法中setOuterContext语句类似,不同的在于:
//通过ContextThemeWrapper类的attachBaseContext方法,将createBaseContextForActivity中实例化的ContextImpl对象传入到ContextWrapper类的mBase变量,这样ContextWrapper(Context子类)类的成员mBase就被实例化为Context的实现类ContextImpl
attachBaseContext(context);
......
}
Activity通过ContextWrapper的成员mBase来引用了一个ContextImpl对象,这样,Activity组件以后就可以通过这个ContextImpl对象来执行一些具体的操作(启动Service等);
同时ContextImpl类又通过自己的成员mOuterContext引用了与它关联的Activity,这样ContextImpl类也可以操作Activity。
3.2Service中ContextImpl实例化源码分析
private void handleCreateService(CreateServiceData data) {
......
//类似上面Activity的创建,这里创建service对象实例
Service service = null;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
......
}
try {
......
//不做过多解释,创建一个Context对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//特别特别留意这里!!!
//ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Service对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Service)。
context.setOuterContext(service);
Application app = packageInfo.makeApplication(false, mInstrumentation);
//将上面创建的context传入到service的attach方法
service.attach(context, this, data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
......
} catch (Exception e) {
......
}
}
public final void attach(
Context context,
ActivityThread thread, String className, IBinder token,
Application application, Object activityManager) {
//特别特别留意这里!!!
//与上面handleCreateService方法中setOuterContext语句类似,不同的在于:
//通过ContextWrapper类的attachBaseContext方法,将handleCreateService中实例化的ContextImpl对象传入到ContextWrapper类的mBase变量,这样ContextWrapper(Context子类)类的成员mBase就被实例化为Context的实现类ContextImpl
attachBaseContext(context);
......
}
3.3Application中ContextImpl实例化源码分析
当我们写好一个APP以后每次重新启动时都会首先创建Application对象(每个APP都有一个唯一的全局Application对象,与整个APP的生命周期相同)。
创建Application的过程也在ActivityThread类的handleBindApplication()方法完成相关数据操作(具体关于ActivityThread调运handleBindApplication时机等
细节分析与上面Activity雷同,后边文章会做分析)。而ContextImpl的创建是在该方法中调运LoadedApk类的makeApplication方法中实现,
LoadedApk类的makeApplication()方法中源代码如下:
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
//只有新创建的APP才会走if代码块之后的剩余逻辑
if (mApplication != null) {
return mApplication;
}
//即将创建的Application对象
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
initializeJavaContextClassLoader();
}
//不做过多解释,创建一个Context对象
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//将Context传入Instrumentation类的newApplication方法
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
//特别特别留意这里!!!
//ContextImpl中有一个Context的成员叫mOuterContext,通过这条语句就可将当前新Application对象赋值到创建的ContextImpl的成员mOuterContext(也就是让ContextImpl内部持有Application)。
appContext.setOuterContext(app);
} catch (Exception e) {
......
}
......
return app;
}
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
newApplication
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
......
//继续传递context
app.attach(context);
return app;
}
attach
final void attach(Context context) {
//特别特别留意这里!!!
//与上面makeApplication方法中setOuterContext语句类似,不同的在于:
//通过ContextWrapper类的attachBaseContext方法,将makeApplication中实例化的ContextImpl对象传入到ContextWrapper类的mBase变量,这样ContextWrapper(Context子类)类的成员mBase就被实例化为Application的实现类ContextImpl
attachBaseContext(context);
......
}
4,各种Context的使用,注意事项
4.1 getApplication和getApplicationContext的区别:
4.2 context引起的内存泄漏问题:
public class CustomManager { private static CustomManager sInstance; public static CustomManager getInstance(Context context) { if (sInstance == null) { sInstance = new CustomManager(context); } return sInstance; } private Context mContext; private CustomManager(Context context) { mContext = context; } }
public class CustomManager {
private static CustomManager sInstance;
public static CustomManager getInstance(Context context) {
if (sInstance == null) {
sInstance = new CustomManager(context.getApplicationContext());
}
return sInstance;
}
private Context mContext;
private CustomManager(Context context) {
mContext = context;
}
}
public class MyCustomResource {
//静态变量drawable
private static Drawable drawable;
private View view;
public MyCustomResource(Context context) {
Resources resources = context.getResources();
drawable = resources.getDrawable(R.drawable.ic_launcher);
view = new View(context);
view.setBackgroundDrawable(drawable);
}
}
public void setBackgroundDrawable(Drawable background) {
..........
/**此处的this就是当前View对象,而View对象又是有Context对象获得
因此,变量background持有View对象的引用,View持有Context的引用,
所有background间接持有Context对象的引用了*/
background.setCallback(this);
.......
}