当您调用getApplicationContext()时,会调用哪个代码?

10

我出于兴趣研究了Android的源代码。我发现Context是一个带有抽象方法的抽象类:

public abstract Context getApplicationContext();

ContextWrapper.java继承自Context.java,这导致了getApplicationContext()方法的实现:

 @Override
    public Context getApplicationContext() {
        return mBase.getApplicationContext();
    }

但是mBase是一个指向Context类型对象的引用,它在ContextWrapper的构造函数中进行初始化:

public ContextWrapper(Context base) {
    mBase = base;
}

那么这个 mBase 引用是指一个 抽象类 吗?嗯,我只是不明白当你从你的 Activity 调用 getApplicationContext() 方法时执行的代码在哪里。


你理解抽象类的工作原理吗?某个具体的类在某处extends Context,并且这就是方法实现的地方。 - Matt Ball
我对它的位置很感兴趣,我理解抽象类的工作原理。 - Eugene
1个回答

16
这是一个有趣的多态示例。
只要您的“base”扩展了“Context”,它就必须提供getApplicationContext()的实现,对于ContextWrapper来说,这是您在此处提供的代码。 这里有这个实现和ContextImpl中的实现
阅读您提供的代码时,需要注意以下几点:ContextWrapper本身扩展了Context,但它还需要一个Context输入(可以是ContextWrapper、Service、Application或Activity)。ContextWrapper不关心它是哪种类型;它只知道它们都有一个名为getApplicationContext()的方法,并且希望在被调用时调用该方法。例如,它可以传递另一个ContextWrapper,但因为该ContextWrapper在其构造函数中也需要一个Context,所以这只会增加另一层嵌套。
Application类继承了ContextWrapper类,并调用super(null)方法。如果保持这种方式,则getApplicationContext()方法会抛出NullPointerException。然而在ContextWrapper中,它也可以通过attachBaseContext(Context)进行设置,这就很有意思了。

ActivityApplication 都有一个方法叫做 attach(Context [...other stuff])。每个方法都会使用传入的 Context 调用 attachBaseContext()

  • Instrumentation类中,你会找到android.app.Instrumentation.newApplication(),它创建了一个ContextImpl,并将其传递给一个Application
  • ActivityThread类中,你会找到handleBindApplication,它创建了一个ContextImpl,并将其作为根Context传递给Activity
  • LoadedApk类中,你会找到makeApplication,它创建了一个ContextImpl,并将其传递给一个Application这里是它被调用的地方。
在一天结束时,mBase 通常最终成为 ContextImpl
在查找所有这些内容时可能有用的链接:

谢谢你的回答,Jon。我很困惑,因为在Application.javaService.java中都没有这个方法的实现。那么这个方法的实现在哪里呢? - Eugene
1
实现在ContextWrapper中。关键信息是mBase会在Activity或Application初始化时发生运行时变化。 - Jon O
感谢您如此详细的研究和解释! - Eugene
这绝对是我读过的关于ContextWrapper代理对象和ContextImpl对象(Context的实际实现者)之间关系以及Activity和Application等类如何与它们交互的最佳SO帖子。感谢你的撰写Jon。 - M.Ed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接