Activity基础


Android四大组件之一——Activity.

Ps 网上搜集

##1 Activity的生命周期

1 Activity生命周期

  • Activity主要的三种状态:

      Running(运行):在屏幕前台(位于当前任务堆栈的顶部)

      Paused(暂停):失去焦点但仍然对用户可见(覆盖Activity可能是透明或未完全遮挡)

      Stopped(停止):完全被另一个Activity覆盖

其生命周期示意图如下:

  • onCreate——创建Activity
    当Activity第一次创建的时候调用。这个方法里主要是提供给我们做一些初始化操作,如:创建view、绑定数据到view。onCreate在整个生命周期只会初始化一次外,他还有一个很重要的作用:当我们的Activity非正常销毁之后,例如手机旋转,内存不足导致的后台自动销销毁。为了保护我们的数据可以将数据保存在savedInstanceState中,当Activity重启数据依旧不会消失。我们可以通过onCreate方法中的savedInstance参数拿到我们的数据。

做法很简单只要重载onSaveInstanceState或者onRestoreInstance就可以了:

1
2
3
4
5
6
7
8
9
Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
}
  • onStart —Activity变成可见
    该方法的执行表示Activity已经可见了但是还无法和用户交互,只有当执行到onResume方法的时候才可以进行交互。如果activity开启了另一个不完全覆盖的activity B,而再次关闭这个B的时候,将不会执行这个方法,但是会执行onResume。也就是说,onstart在每次变得可见的时候才会执行一次。

  • onResume — Activity处于运行状态,获得用户焦点
    当用户从pause的状态resume到你的activity的时候,系统调用了onResume()的函数。onResume()会用来初始化在onPause()中释放的组件,并且执行一些其他在当activity进入resume状态的时候需要执行的初始化调用。此时Activity就会位于Activity栈的栈顶,并且可以与用户开始进行交互了。

  • onPause – 其他Activity获得用户焦点
    一般的在app使用中,前台的activity一般是会被视觉组件所遮住的,这就会导致activity的pause。一旦这个activity全部被遮住了,并且不可见,它就stop了。当你的activity收到了一个调用onPause()的请求,它可能表示这个activity将会被停止一段时间并且使用者很可能会再次回到你的activity来。但是这也很可能表示着用户正在离开你的app。在该方法中google给出的建议是存储一些重要的数据同时停止一些类似于动画等消耗CPU的工作。该方法的调用过程是很快的,否则会影响到后面的Activity的实现,所以在该方法里不宜做过多耗时操作。

  • onStop — Activity不再可见,处于停止状态
    Activity在不可见的时候,如被其他Activity完全覆盖,此Activity就处于onStop状态。此时如果Activity再次启用,调用onRestart,复活;如果Activity被销毁,调用onDestroy。销毁有两种原因:主动调用finish()或被系统回收。

  • onRestart
    onStop方法之后可能会调用到onRestart方法,这是因为代表的Activity正在被重新启动,然后紧接着就会继续走到onStart和onResume方法中。以下三种情况会调用:a.按下home键之后,然后切换回来,会调用onRestart();b.从本Activity跳转到另一个Activity之后,按back键返回原来Activity,会调用onRestart();c.从本Activity切换到其他的应用,然后再从其他应用切换回来,会调用onRestart();

  • onDestroy — Activity被销毁了
    在Activity的生命周期中,onDestory()方法是他生命的最后一步,资源空间等就被回收了。当重新进入此Activity的时候,必须重新创建,执行onCreate()方法。‍这里需要提到的一点是,即使一个Activity被销毁后app内部的static变量是不会被销毁的,因为static变量是全局的,activity销毁但是该app的进程并没有被杀死。所以说这一点尤为需要注意我们的static变量的使用,否则稍有不慎再次启动该activity的时候该static变量就会是一个dirty data!

2.生命周期分析

1).启动Activity->返回桌面->再次回到Activity
根据前面对生命周期的分析可以不难知道这三个过程Activity的生命周期方法调用顺序如下:
onCreat()——>onStart()——>onResume()
返回桌面则会调用:onPause()——>onStop()
再次回到Activity:onResart()——>onStart()——>onResume()

2).按back退出activity
此时会走onPause()——>onStop()——>onDestroy()方法
再次强调的是该方法即使退出了主Activity但是也没有杀掉进程,所以static变量并没有被销毁,再次进来的时候可能会是脏数据。就以我的经验碰到的最多的一个问题就是:有的时候会将一些名字什么的存在static变量里作为全局变量进行调用,此时测试人员的其中一个case会按back退出activity然后切换系统语言再次启动app。如果没有对static变量做一些销毁操作的话,再次回来就是一个dirty data,语言文字并没有切换导致了bug的存在。

3).在一个Activity中启动另一个Activity
从MainActivity中启动SecondActivity我们可以很清楚的看到MainActivity中的onPause方法执行完了以后然后新的SecondActivity的onCreate、onStart、onResume方法就会依次执行将SecondActivity显示出来,最后MainActivity的onStop方法才会被调用。这同时也验证了之前提到的,google并不建议在onPause方法里进行一些耗时操作,否则会影响SecondActivity的创建。

##2 Activity四种启动模式

###1 standard
默认模式,可以不用在AndroidManifest.xml里对应的标签设置android:launchMode属性。在这个模式下,每次创建Activity都会默认创建一个新的实例。因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
假设我有一个Activity名为A1, 上面有一个按钮可跳转到A1。那么如果我点击按钮,便会新启一个Activity A1叠在刚才的A1之上,再点击,又会再新启一个在它之上……
点back键会依照栈顺序依次退出。

###2 singleTop
可以有多个实例,但是不允许多个相同Activity叠加。即,如果Activity在栈顶的时候,启动相同的Activity,不会创建新的实例,而会调用其onNewIntent方法。
假设有一个Activity为A1,其有一个按钮可以跳到A1.若我意图打开的顺序为A1->A1->A1,则实际上只会在第一次打开时创建A1(后两次意图打开A1,实际只调用了前一个的onNewIntent方法)

3 singleTask

只有一个实例。在同一个应用程序中启动它的时候,若Activity不存在,则会在当前task创建一个新的实例,若存在,则会把task中在其之上的其它Activity destory掉并调用它的onNewIntent方法。如果是在别的应用程序中启动它,则会新建一个task,并在该task中启动这个Activity,singleTask允许别的Activity与其在一个task中共存,也就是说,如果我在这个singleTask的实例中再打开新的Activity,这个新的Activity还是会在singleTask的实例的task中。

若我的应用程序中有三个Activity,C1,C2,C3,三个Activity可互相启动,其中C2为singleTask模式,那么,无论我在这个程序中如何点击启动,如:C1->C2->C3->C2->C3->C1-C2,C1,C3可能存在多个实例,但是C2只会存在一个,并且这三个Activity都在同一个task里面。
但是C1->C2->C3->C2->C3->C1-C2,这样的操作过程实际应该是如下这样的,因为singleTask会把task中在其之上的其它Activity destory掉。
操作:C1->C2 C1->C2->C3 C1->C2->C3->C2 C1->C2->C3->C2->C3->C1 C1->C2->C3->C2->C3->C1-C2
实际:C1->C2 C1->C2->C3 C1->C2 C1->C2->C3->C1 C1->C2

若是别的应用程序打开C2,则会新启一个task。
如别的应用中有一个activity,taskId为200,从它打开C2,则C2的taskId不会为200,例如C2的taskId为201,那么再从C2打开C1、C3,则C1、C3的taskId仍为201。

4 singleInstance

只有一个实例,并且这个实例独立运行在一个task中,这个task只有这个实例,不允许有别的Activity存在。
例如:程序有三个ActivityD1,D2,D3,三个Activity可互相启动,其中D2为singleInstance模式。那么程序从D1开始运行,假设D1的taskId为200,那么从D1启动D2时,D2会新启动一个task,即D2与D1不在一个task中运行。假设D2的taskId为201,再从D2启动D3时,D3的taskId为200,也就是说它被压到了D1启动的任务栈中。
若是在别的应用程序打开D2,假设Other的taskId为200,打开D2,D2会新建一个task运行,假设它的taskId为201,那么如果这时再从D2启动D1或者D3,则又会再创建一个task,因此,若操作步骤为other->D2->D1,这过程就涉及到了3个task了。

3 Activity生命周期 onNewIntent

当我们在manifest文件里对Activity的launchmode进行设置为singleTop、singleTask、singleInstance的时候都会有可能调用到此方法.Activity第一启动的时候执行onCreate()—->onStart()等后续生命周期函数,也就时说第一次启动Activity并不会执行到onNewIntent().如果不是复用之前的activity实例是不会调用onNewIntent)而后面如果再有想启动Activity的时候,那就是执行onNewIntent()—->onResart()——>onStart()—–>onResume(). 如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()—->onStart()—->onResume()等。
当调用到onNewIntent(intent)的时候,需要在onNewIntent() 中使用setIntent(intent)赋值给Activity的Intent.否则,后续的getIntent()都是得到老的Intent。