10

I have looked into Android sources just out of interest. What I found is that Context is an abstract class with abstract method:

public abstract Context getApplicationContext();

The ContextWrapper.java extends Context.java which led to implementation of getApplicationContext() method:

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

But mBase is reference to an object of type Context which is initialized in ContextWrapper's constructor:

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

So this mBase reference refers to abstract class? Well, I just don't understand where is the code which is executed when you call getApplicationContext() from your Activity.

Eugene
  • 59,186
  • 91
  • 226
  • 333
  • Do you understand how abstract classes work? There's some concrete class somewhere which `extends Context`, and that's where the method is implemented. – Matt Ball Aug 22 '12 at 18:38
  • I'm interested where it is, I understand how abstract classes work. – Eugene Aug 22 '12 at 18:39

1 Answers1

16

This is an interesting example of polymorphism.

As long as your base extends Context, it has to provide an implementation of getApplicationContext(), which in the case of ContextWrapper is the code you provided here. There's this implementation, and the one in ContextImpl.

It's important to note a couple of things when reading the code you provided: ContextWrapper itself extends Context, but it also takes a Context as an input (which could be a ContextWrapper, or a Service, or an Application, or an Activity). ContextWrapper doesn't care which kind it is; it just knows that they have a method getApplicationContext and it wants to call that method when asked. (For example, it could be passed another ContextWrapper, but because said ContextWrapper would also require a Context in its constructor, that would just add another level of nesting.)

The Application extends ContextWrapper class calls super(null), which would mean that getApplicationContext() would throw a NullPointerException if it were left that way--however, in ContextWrapper it's also settable by attachBaseContext(Context), and this is where it gets interesting.

Both Activity and Application have methods attach(Context [...other stuff]). Each of them calls attachBaseContext() with the passed-in Context.

  • In the Instrumentation class, you'll find android.app.Instrumentation.newApplication(), where a ContextImpl is created, and passed into an Application.
  • In the ActivityThread class, you'll find handleBindApplication which creates a ContextImpl that gets passed to the Activity as its root Context.
  • In the LoadedApk class, you'll find makeApplication which creates a ContextImpl that gets passed to an Application. Here are the places it's called.

So, at the end of the day, mBase typically ends up as a ContextImpl.

Potentially useful links I looked at while finding all of this out:

Jon O
  • 6,532
  • 1
  • 46
  • 57
  • Thank you for your answer, Jon. I'm confused because there is no implementation of this method nor in `Application.java` neither in `Service.java`. Where is the implementation? – Eugene Aug 22 '12 at 18:54
  • 1
    The implementation is in `ContextWrapper`. The key bit of information is that `mBase` changes at run-time as an Activity or Application is initialized. – Jon O Aug 22 '12 at 19:05
  • Thanks for such a detailed research and explanation! – Eugene Aug 22 '12 at 19:36
  • This is hands down, the best SO post I've ever read about the relation between the ContextWrapper proxy object and the ContextImpl object (the real implementor of Context), and how classes such as Activity and Application interact with them. Thanks for the writeup Jon. – M.Ed Oct 28 '22 at 15:06