很简单的一个问题,但是回答起来却不是那么简单哈!
如果面试的时候问起来的话,你就需要明白以下问题:
- 了解Context的作用
- Context的初始化流程
- 深入了解不同应用组件之间的Context的区别。
刚开始学习android的时候,只是官方对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.
*/
这是个什么意思?翻译过来就是:
它是一个用来描述关于应用环境全局信息,由安卓系统提供实现的抽象类。它可以让我们访问应用特殊的系统资源和类,也提供应用层级的一些操作,比如:启动activity,发送广播和接收intent等等。
反正大概意思就是说,我们可以通过这个玩意儿来访问系统资源,以及进行一些特殊操作。这个我们就当做Context的作用吧!
不过说是说了,用也会用,但是为什么他有这种功能?
那就要看他们的具体实现了!
先看一下Context.java抽象类的结构:
大家可以看到一系列的非常熟悉的方法:
- getApplicationContext()
- getApplicationInfo()
- bindService()
等等等等…
然后,这些方法的具体实现呢?当然是在ContextImpl.java中:
我们摘取其中的一个方法看看具体实现:
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
对应其中的warnIfCallingFromSystemProcess()方法如下:
private void warnIfCallingFromSystemProcess() {
if (Process.myUid() == Process.SYSTEM_UID) {
Slog.w(TAG, "Calling a method in the system process without a qualified user: "
+ Debug.getCallers(5));
}
}
可以看出,这里不是bindService流程的关键,继续查看bindServiceCommon(),可以看到:
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null) {
throw new IllegalArgumentException("connection is null");
}
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, getOpPackageName(), user.getIdentifier());
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
很明显可以看出,最终此处调用到了ActivityManagerNative中进行bindService。也就说,我们在Activity中采用Context进行调用的时候都是调用到了ContextImpl.java中。看到一个东西的本质才能知道他是咋回事。
为什么在组件中采用Context调用对应方法对对应到ContextImpl中,就需要看其实现过程。
实现过程预留,后续补充
深入了解不同应用组件之间的Context的区别
在安卓系统中有哪些组件有Context?
答:Application,Activity,Service
不同组件之间的Context是否有差别?
public class Application extends ContextWrapper implements ComponentCallbacks2 {
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback {
public class ContextThemeWrapper extends ContextWrapper {
此处可以明显看出,三者之间的继承的类是不同的,梳理一下代码,可以找到他们的继承关系:
三者继承的不同点就是在于Activity继承的是ContextThemeWrapper,原因是Activity有UI显示,所以需要添加一些系统资源的访问,所以就多了一个Theme。
然后,对于Context的创建过程:
- ActivityThread: handleBindApplication()
- Application app = data.info.makeApplication(data.restrictedBackupMode, null);
- LoadedApk.java:
public Application makeApplication()
.....
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
- 然后执行到了ContextImpl.java中:
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
return new ContextImpl(null, mainThread,
packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
}
//此处通过反射创建一个类实例
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
public Application newApplication(ClassLoader cl, String className, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return newApplication(cl.loadClass(className), context);
}
static public Application newApplication(Class<?> clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
return app;
}
//Application.java
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
此处一个重要函数,就是attachBaseContext();查看其实现:
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
也就是说,此处将创建的context实例传入到了ContextWrapper中,具体方法实现都是从这里调用ContextImpl中的犯法。此处用到了静态代理
…
后续待更…