onApplyThemeResource():
一般来说在AndroidManifest.xml的application标签下会全局设置一个theme属性,或者单独为每个activity设置也可以,这样onApplyThemeResource()方法会先于onCreate()调用,当然你若是不在AndroidManifest.xml设置,硬是单单在onCreate()里面调用setTheme()方法也是可以的,这样onApplyThemeResource()就会在onCreate()后调用了。
这个方法顾名思义就是activity应用主题资源的,当然并不是说activity直接就调用onApplyThemeResource()了,我们可以稍微追踪下它的调用路线。
Android——Activity的各回调方法(2)
我们知道要启动一个activity,会调用ActivityThread的performLaunchActivity()方法来创建这个activity,下面我们点进去找到关于设置主题的几行代码。

Android——Activity的各回调方法(2)
然后去activity的setTheme()里面看看,看之前先了解下activity的继承关系,如下图。activity是直接继承自ContextThemeWrapper类的,所以才具有了变换主题的能力,实际上activity的setTheme()方法即是ContextThemeWrapper的setTheme()方法。
Android——Activity的各回调方法(2)
点进去ContextThemeWrapper的setTheme()方法:
Android——Activity的各回调方法(2)
然后initializeTheme():
Android——Activity的各回调方法(2)
以上用语言来表示就是,activity在创建的时候,如果有在AndroidManifest.xml里面设置有效的主题资源id,就会在onCreate()之前调用setTheme()方法,然后调用initializeTheme()方法,进而回调onApplyThemeResource()方法;其实前面看ActivityThread的performLaunchActivity()方法的时候,除了关于设置主题的代码外,上面还多了几行代码,为什么要把它提出来呢,因为initializeTheme()方法有个getBaseContext()的方法,那多出来的几行代码就是为了此刻来说明下的。看看Contextwrapper类的源码,发现它有一个名为mBase的Context类型的成员变量,这个mBase变量委托Contextwrapper类来调用自己的所有方法,大概就是下面这样:
Android——Activity的各回调方法(2)
所以initializeTheme()方法调用的getBaseContext()方法取的就是这个名为mBase的Context类型的成员变量,但是实际上Context类是一个抽象类,里面根本没有任何实现,这个时候就要重新回到上面的performLaunchActivity(),看看那多出来的两行代码到底干了什么。
首先是createBaseContextForActivity()方法,只贴重要的代码,其它的不想看:
Android——Activity的各回调方法(2)
然后是Activity的attch()方法,就不贴代码了,点进去发现调用了attachBaseContext()方法,对了,实则调用的就是上面ContextWrapper类的attachBaseContext(),由此,分析得知,activity在创建的时候通过createBaseContextForActivity()得到一个Context的实现类ContextImpl类的实例,然后在attch()方法里面通过调用attachBaseContext()方法让ContextWrapper类的mBase成员变量指向这个实例.
综上所述,前面initializeTheme()方法里面的getBaseContext()就说得通了,它实际得到的是一个ContextImpl类的实例,Activity第一次设置主题的时候,ContextImpl类的getTheme()方法会根据你的targetSdkVersion版本返回一个对应的默认的主题对象。以后有时间再去看看ContextImpl类,现在先跳过这个实际开发没什么用的onApplyThemeResource()方法。
onContentChanged():
当屏幕的内容视图发生改变时会调用,官方文档上的这句话反正我是看不大明白,只能看看源码了。这里以AppCompatActivity为例,发现AppCompatActivity的setContentView()或者addContentView()方法都是通过AppCompatDelegate来委托调用的,于是我们找到它的实现类AppCompatDelegateImplV7,然后把这两个方法贴出来如下:
Android——Activity的各回调方法(2)
所以,Activity在onCreate()里边调用setContentView()方法或者addContentView()方法的时候,都会紧接着回调onContentChanged()方法,上面代码mOriginalWindowCallback变量指向的就是委托的Activity对象。根据上述分析,onContentChanged()方法什么时候会回调呢?就是当Activity的根视图中id为android.R.id.content的ViewGroup的子View发生改变时,这种改变指的是子View的替换。这样来看的话,我们在onCreate()里边就不用写个initView()的方法来findViewById()了,直接把这些操作丢在onContentChanged()方法里边,感觉吊吊的。遗憾的是,有了butterknife、AndroidAnnotations、Dagger亦或是其它的注解框架,谁还会用findViewById()?
当然,也可以直接看看Activity里边的setContentView()方法,然后看看PhoneWindow类里边的setContentView()方法,原理是一样的。那么这个id为android.R.id.content的ViewGroup到底是什么呢?以后有时间的话要单独记录下有关DecorView的知识
onPostCreate():
照例把官方文档翻译一下,当activity已经完全启动的时候会回调这个方法,系统会在里边做一些最终的初始化,我们的应用程序通常不用重写这个方法。 嗯,就这样,但是总感觉少了点什么,去ActivityThread类的performLaunchActivity()方法里面看看:
Android——Activity的各回调方法(2)

看到这,我突然发现不管是onPostCreate()还是onPostResume(),Activity的默认实现操作都是跟标题栏有关,或者说跟ActionBar有关,我觉得这不是一个巧合,你看ActionBarDrawerToggle也是。所以,我觉得当设备状态变化时,比如横竖屏转换的时候,如果我们没有在AndroidManifest.xml配置configChanges属性,当Activity重新回调各生命周期方法的时候,我们在这两个方法里面同步ActionBar的状态是否会比较符合官方的思想。

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-08-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-12-24
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-01
  • 2022-12-23
  • 2021-05-18
相关资源
相似解决方案