面试答题:Context到底是一种什么东西?

很简单的一个问题,但是回答起来却不是那么简单哈!
如果面试的时候问起来的话,你就需要明白以下问题:

  • 了解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中的犯法。此处用到了静态代理

后续待更…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值