Activity基础全面总结

Android发展也有十几年了。也许在很多Android开发者看来写Activity的文章已经意义不大。因为网络上已经也有太多太多这样的文章。此偏文章的目的是全面总结基础知识。将Acitivity中的生命周期,异常情况下的生命周期,启动模式,Flage,IntentFilter进行一个全面的总结,达到一篇文章全面理解所有Acitivity基础知识。

一、什么是Activity(活动):

活动可以通俗理解为我们看到的界面,其中可以设置可视化的布局,并响应我们和它的交互事件。

二、什么是生命周期?

对于一个页面来讲,它从开始创建到完全销毁是它的完整生命周期,其中会有许多方法会被在各个阶段调用执行,简称生命周期方法。

三、Activity的生命周期方法:
  • onCreate:在Activity被创建的时候调用。其中会进行一些设置布局和初始化操作(如:点击事件)。
  • onStart:表示Activity正在启动,此时的Activity已经可以被看见,但是还无法进行交互操作。
  • onResume:表示Activity已经可被看见,并且已经可以进行交互。
  • onPause:表示Activity正在暂停,处于不可交互,此方法中我们可以处理轻量级的工作,比如停止动画,和简单的数据存储,不能进行太耗时的操作,因为只有在这个方法执行完成之后,第二个Activity才会被创建并显示。
  • onStop:表示Activity已经停止,完全可见状态,在第二个Activity的onResume:方法执行完成之后执行,此时的Activity可能因为系统内存不足被销毁。此方法中可以进行一些稍微重量级的回收工作,同样不能太耗时。
  • onDestory:表示Activity正在被销毁,(不一定会调用。被系统内存不足销毁的时候不会调用此方法)我们可以在这里处理一些回收和最终的资源释放。
  • onRestart:表示Acitivity从后台onStop状态回到前台,会在onStart方法前调用。
Activity基础全面总结_第1张图片
Activity生命周期
四、正常情况下的生命周期。
  • 单个Activity的销毁到结束:我们创建一个MainActivity然后在上面的生命周期方法中打印log日志。我们开始运行,并使用back键进行销毁。
    onCreate → onStart → onResume→ onPause→ onStop→ onDestroy
  • 两个Activity,MainActivity中创建一个Button用来打开SecondActivity。使用Back键销毁SecondActivity和MainActivity。
    (M)onCreate → (M)onStart → (M)onResume→ 点击Button→(M)onPause→(S)onCreate → (S)onStart → (S)onResume→ (M)onStop→ 点击Back返回MainActivity→ (S)onPause→ (M)onRestart→ (M)onStart → (M)onResume →(S)onStop→(S)onDestroy→ 点击Back销毁MainActivity→(M)onPause→(M)onStop→(M)onDestroy
    总结:当一个Activity跳转到另一个Activity时,总是先调用第一个Acitivity的onStop方法,然后等到第二个Activity执行完onResume方法之后,才继续往下执行自己的生命周期方法。
  • 一个Activity和一个DialogActivity,MainActivity中创建一个Button用来打开ThirdDialogActivity。使用Back键销毁ThirdDialogActivity和MainActivity。
    (M)onCreate → (M)onStart → (M)onResume→ 点击Button→(M)onPause→(S)onCreate → (S)onStart → (S)onResume→ 点击Back返回MainActivity→ (S)onPause → (M)onResume →(S)onStop→(S)onDestroy→ 点击Back销毁ThirdDialogActivity→(M)onPause→(M)onStop→(M)onDestroy
    总结:当打开一个DialogActivity的时候,MainActivity处于可见不可交互状态,此时MainActivity的onPasue方法会执行onStop不会执行,当返回MainActivity的时候也只会执行onResume方法。
  • Google文档表示,当Activity处于后台只时,当内存不足时可能会被销毁。并不会执行Activity的onDestory方法,当返回这个Activity时会调用onCreate方法。
五、非正常情况下的生命周期
  • 当Activity横竖屏切换的时候,Activity会被销毁并重新创建。此时为异常生命周期调用,并且Activity生命周期会重新创建1次,而Fragment会被重新创建两次。
    Activity被异常创建的原因是因为系统配置发生了变化。从横屏切换到了竖屏。因为配置发生了变化会去改变它要加载的很多资源,如横竖屏时系统会加载不同的布局文件。
    如果想要Activity在横竖屏切换的时候不去重新创建Activity,在清单文件中设置如下配置,设置之后,onConfigurationChanged方法将会被调用。
 targetSdkVersion <=12
android:configChanges="orientation"

 targetSdkVersion >12
android:configChanges="orientation|screenSize"
  • 资源内存不足的时候导致优先级低的Activity被杀死。
    前台可见的Activity优先级是最高的,当Activity处于后台不可见的时候,即onStop,并未onDestory。系统在内存不足的情况下有可能杀掉这个Activity,后台进程中的Activity被杀掉的时候是不会调用其onDestory方法的,这个很难去模拟。

  • 上边说过当系统配置发生改变之后,Activity会被重新创建。我们设置configChanges可以避免这种被重新创建。我们通过下面一张图片来了解这个属性中可以设置的值的含义,设置多个值的时候用" | ”相连接。


    Activity基础全面总结_第2张图片
    configChanges属性介绍
六、异常状态下的数据保存
  • 通过上面的异常情况我们知道Activity可能会被销毁重新创建,当我们这个Activity中有一些用户输入的数据,在重新创建的时候不进行恢复的话,会给用户带来不好的体验。而在这种情况下,Google给我们提供了onSaveInstanceState(Bundle outState)和onRestoreInstanceState(Bundle savedInstanceState)这对方法供我们去使用。我们可以在onSaveInstanceState中通过Bundle来保存我们想要恢复的数据,在onRestoreInstanceState中进行恢复,其实恢复的地方还可以在onCreate方法中进行,onCreate方法提供了Bundle参数也可以用来恢复数据。记得判断Bundle是否为空。
    注意:系统只在Activity异常终止的时候才会调用onSaveInstanceState与onRestoreInstanceState来储存和恢复数据,其他情况不会触发这个过程。但是按Home键或者启动新Activity仍然会单独触发onSaveInstanceState的调用。
    onSaveInstanceState在onStop之前被调用,和onPause没有先后顺序,onRestoreInstanceState在onCreate之后被调用。
  • 委托机制:当Activity被异常销毁之后,他会委托给Window保存数据,而Window会让我们的顶层容器DecorView去保存数据,而我们的DecorView,而我们的顶层呢个容器DecorView会委托我们的所有子View去保存我们的数据。而想要看我们每个子View都能自己保存什么样的数据,可以自己去我们的子View当中去查看onSaveInstanceState和onRestoreInstanceState的源码。
七、Activity的启动模式(launchMode)

了解启动模式之前我们先了解一个概念,任务栈,所谓任务栈,就像我们的手枪弹夹一样,我们把一颗颗子弹压入弹夹,当再想取出子弹的时候,总是把最后一个压入弹夹的子弹最先取出来,这就是一个任务栈,原则:先入后出。
而对于Activity来讲我们可以指定他的返回栈,通过xml中设置TaskAffinity属性,必须与包名不同。
我们可以使用 adb shell dumpsys activity查看Activity所属任务栈。

  • standard(默认):
    1、当B页面被A页面打开之后,B将会被创建放入A的返回站内,置于栈顶。无法指定TaskAffinity属性。
    2、当启动B的页面为ApplicationContext的时候,将会报错,因为ApplicationContext没有所谓的返回栈,只有将B设置flage为FLAGE_ACTIVITY_NEW_TASK才行,此方法其实是把B设置为singleTask启动模式,会创建一个新的任务栈。
  • singleTop(单一顶部);
    1、当Acitivity 已经在栈顶的时候,将不会创建新的Activity实例。同时会调用他的onNewInstance方法。如果Activity已经不在顶部,将会重新创建事例放置在栈顶。
    2、和standard一样此启动模式无法指定TaskAffinity属性,Acitivity都将放入在启动它的任务栈之内。
  • singleTask(栈内复用模式):
    1、当Activity没有指定taskAffinity属性的时候,Activity默认的任务栈为包名的启动栈,当被打开的时候,首先查看启动栈是否存在,如果存在,查看栈中是否有实例存在,如果存在,把栈中在Acitivity之上的所有实例清空,将Acitivity显示出来,并调用onNewIntent方法
    2、当Acitivity指定taskAffinity属性,并且打开的singleTop、standard、任务栈相同的singleTask启动模式的Acitivity的时候,两个Acitivity都会在同一个栈中,并且,为前台任务栈。
  • singleInstance:(单实例模式)
    1、当Acitivity使用singleInstance,Acitivity会创建一个新的任务栈并且独享这个任务栈。再次打开他的时候会调用onNewIntent方法并不会重新创建。
    2、此Acitivity打开新的standard、singleTop模式的Acitivity也不会将他们放在自己的任务栈中
    3、singleInstance打开一个singleTask,两个Activity的TaskAffinity属性指定为一样。也不会放在同一个栈中。
    4、singleInstance不指定TaskAffinity属性,也会创建一个新的任务栈。
八、Activity的Flags

flage不是启动模式,要将他们区分开。

  • FLAG_ACTIVITY_NEW_TASK:会判断有没有他想要的任务栈(TaskAniffity)。如果没有创建他的要的任务栈并压入。如果有看是不是在栈顶,如果是在栈顶复用,调用onNewIntent,如果不是在栈顶,创建一个新的Activity压入栈。用在service或者广播打开Acitivity的时候用此标记。
  • FLAG_ACTIVITY_SINGLE_TOP:和启动模式singleTop相同。
  • FLAG_ACTIVITY_CLEAR_TOP:如果是默认模式启动的Acitivity设置此标记位,那么这个Activity和他之上的Activity都要出栈,并被重新创建放入栈顶。这个标记位和singleTop启动模式一起使用,其效果和singleTask启动模式一摸一样,只是无法设置TaskAffinity指定任务栈。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:标记这个标记的Acitivity不会出现历史Acitivity的列表中,不会后退回来。和xml中设置android:excludeFromRecents="true"一样
九、IntentFilter的匹配规则
  • action:必须匹配的。只要有 就要一样,区分大小写,可以设置多个,匹配上一个就行。
  • category:
    1、首先必须有一个 ,否则是接收不到隐式启动的。
    2、Intent中如果有category,那就必须每个都要匹配的上。
  • data:如果定义了data Intent中必须设置data 而且必须匹配的上。和action规则一样
                

如果过滤规则中没有指定URI规则,但是URI却有默认值,file和content,我们的Intent的URI部分的scheme必须是content或者file才能匹配的上。
必须使用Intent.setDataAndType。因为setData 和setType会互相清空对方的值。
我们可以使用PackageManager提供的两个方法来验证我们的intent是否能匹配到Activity 防止我们打开Acitivty的时候出现找不到的异常。
resolveActivity 和queryIntentActivities 他们的参数中flage我们设置为MATCH_DEFAULT_ONLY。标记此是为了将有default的category的返回给我们,因为如果没有这个category,Activity将不会收到隐式调用。resolveActivity 返回的是最佳匹配的集合 queryIntentActivities 返回的是所有能匹配上的集合。

你可能感兴趣的:(Activity基础全面总结)