Ответ 1
Это интересный пример полиморфизма.
Пока ваш base
extends Context
, он должен обеспечить реализацию getApplicationContext()
, которая в случае ContextWrapper
- это код, указанный здесь. Там эта реализация и одна в ContextImpl
.
Важно отметить пару вещей при чтении кода, который вы указали: ContextWrapper
сам расширяет Context
, но он также принимает Context
как вход (который может быть ContextWrapper
, или Service
, или Application
, или Activity
). ContextWrapper
не волнует, какой он; он просто знает, что у них есть метод getApplicationContext
, и он хочет вызвать этот метод, когда его спросят. (Например, ему может быть передан другой ContextWrapper
, но поскольку упомянутый ContextWrapper
также потребует Context
в его конструкторе, который просто добавит еще один уровень вложенности.)
Класс Application extends ContextWrapper
вызывает super(null)
, что означало бы, что getApplicationContext()
будет бросать NullPointerException
, если он оставлен таким образом, однако в ContextWrapper
он также настраивается на attachBaseContext(Context)
, и это где он становится интересным.
Оба Activity
и Application
имеют методы attach(Context [...other stuff])
. Каждый из них вызывает attachBaseContext()
с переданным Context
.
- В классе
Instrumentation
вы найдетеandroid.app.Instrumentation.newApplication()
, где создаетсяContextImpl
и передается вApplication
. - В классе
ActivityThread
вы найдетеhandleBindApplication
, который создаетContextImpl
, который передается вActivity
как его кореньContext
. - В классе
LoadedApk
вы найдетеmakeApplication
, который создаетContextImpl
, который передается вApplication
. Здесь указаны те места, которые он назвал.
Итак, в конце дня mBase
обычно заканчивается как ContextImpl
.
Потенциально полезные ссылки, на которые я смотрел, находя все это: