【Android】四大组件之Activity


Android四大组件之Activity

TopView工作室第一周的笔记

Activity的生命周期

这里由于之前写过相关博客,就重新看了一遍然后参考着写了...

由于异常情况下的关注点与典型情况下有所不同,所以将Activity的生命周期分为以下两个部分来研究:
- 典型情况下的生命周期:在有用户参与下,Activity所经过的Activity所经过的生命周期改变。
- 部分异常情况下的生命周期:Activity被系统回收或者由于当前设备的一些设置发生改变从而导致Activity被销毁重建的生命周期。

典型情况下的生命周期

正常情况下Activity会经历如下的生命周期:

  1. onCreate:表示Activity正在创建。在这里做一些初始化工作,如调用setContentView加载界面布局资源,初始化Activity数据等。
  2. onRestart:当前Activity从不可见状态变为可见状态时调用。一般是用户所致,如按下Home键或打开新的Activity后回到了这个Activity时,就会出现。
  3. onStart:表示Activity正在被启动。这时Activity已经可见了,但没有出现在前台,无法与用户交互。一般理解为已经它已经显示出来了但我们仍然看不到
  4. onResume:表示Activity已经可见了,并出现在了前台并开始活动。和onStart的区别在于onResume时已显示在了前台,我们可以看到它了
  5. onPause:表示Activity正在停止,正常情况下onStop会紧接着调用。特殊情况下,用户用足够快的速度回到当前Activity,那么onResume会接着调用。这种情况是特殊情况,用户操作很难重现。此时一般做一些储存数据,停止动画的工作。但不能太耗时,否则会印象到新Activity的显示。onPause先执行完,新的Activity的onResume才会执行。
  6. onStop:表示Activity即将停止,可做一些稍微重量级回收工作,不过同样不能太耗时。
  7. onDestroy:表示Activity即将被销毁,可以在这里做一些回收工作和最终的资源释放。

不同情况下的回调顺序

  1. 对于一个特定的Activity,第一次启动,回调是这样的:onCreate=>onStart=>onResume。
  2. 当用户打开新的Activity或切换到桌面时,回调是这样的:onPause=>onStop。不过有种特殊情况,如果是透明主题,这里不会回调onStop
  3. 当用户回到原Activity时,回调是这样的:onRestart=>onStart=>onResume。
  4. 用户按Back键回退时,回调是这样的:onPause=>onStop=>onDestroy。
  5. 当Activity被系统回收后再次打开,生命周期方法回调过程与1相同(注:只是生命周期方法相同
  6. 整个生命周期来说,onCreate和onDestroy是配对的,并只可能有一次调用。从Activity是否可见来说,onStart和onStop是配对的,随着用户操作,这两个方法可能调用多次。从Activity是否在前台来说,onResume和onPause是配对的,随着用户操作,这两个方法可能调用多次。

异常情况下的生命周期

Activity除了受用户操作导致的正常生命周期外,还会有一些异常情况,比如当前资源相关系统配置发生改变或者系统内存不足被杀死。下面逐一分析下面的两种情况:

资源相关的系统配置发生改变导致Activity被杀死并重建

首先,我们需要了解一些系统的资源加载机制,《Android开发艺术探索》这本书中做了简单的分析:当我们把一张图片放到drawable目录后,便可以通过Resources来获取这张图片。同时为了兼容不同的设备,我们可能还需要在其他的目录放置不同的图片。比如drawable-mdpi、drawable-hdpi、drawable-land等。这样,应用程序启动时,系统会根据当前设备的情况,加载合适的Resources资源,比如横屏手机和竖屏手机会拿到两张不同的图片(设定了landscape或者portrait状态下的图片)。比如当前Activity处于竖屏状态,如果突然旋转屏幕,默认情况下,Avtivity机会被销毁且重建,不过我们可以阻止系统重建我们的Activity。

默认情况下,如果我们Activity不做特殊处理,那么系统配置改变后,Activity就会被销毁并重建。

系统配置改变后,Activity被销毁,其onPause,onStop,onDestroy均会被调用。同时由于Activity是在异常情况下终止,系统会调用onSaveInstanceState保存当前Activity的状态。(在onStop之前,和onPause没有明显时序关系)注意:这个方法只会在Activity被异常终止的情况下调用,正常情况系统不会回调这个方法。Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数同时传递给onRestoreInstanceState和onCreate方法。因此,我们可以通过onRestoreInstanceState和onCreate方法来判断Activity是否被重建了,如果重建了,就可以取出之前保存的数据并恢复。onResoreInstanceState的调用在onStart之后。

在onSaveInstanceState和onRestoreInstanceState方法中,系统自动为我们做了一定的恢复工作,当Acitivity在异常情况下需要重建时,系统会默认为我们保存当前Activity的视图结构,并在Activity重启后为我们恢复这些数据,比如EditText中用户输入的数据、ListView滚动的位置等。这些View相关的状态系统都能默认为我们恢复。

资源内存不足导致低优先级的Activity被杀死

下面是按优先级从高到低排列的几类Activity:

  1. 前台Activity:正在和用户交互的Activity,优先级最高
  2. 可见但非前台的Activity:如Activity中弹出了对话框,导致Activity可见但无法和用户直接交互。优先级中等。
  3. 后台Activity:已被暂停的Activity,如执行了onStop,优先级最低。

当系统内存不足时,系统就会按上述优先级来杀死Activity所在进程,并在后续通过onSaveInstanceState和onRestoreInstanceState来储存和恢复数据(这里的过程与前文相同)。若一个进程中没有四大组件在运行,它将很快被系统杀死。因此,一些后台哦工作不适合脱离四大组件而独立运行在后台中,这样进程很容易被杀死。比较好的办法是将后台工作放到Service中从而保证进程有一定的优先级,便不会轻易地被系统杀死。

Activity的启动模式

默认情况下,当我们重复启动一个Activity时,系统会创建多个实例并将之放入任务栈中。按下back键后,这些Activity会一一回退。任务栈是一种后进先出的数据结构。每按下back键就会有个Activity出栈,直到栈为空,再按下back键,系统便会回收这个任务栈。可是,多次启动同一个Activity,系统重复创建多个实例,这样不是很傻么?因此,Android提供了启动模式来修改系统的默认行为。目前有下列四种启动模式:

  • standard:标准模式。
  • singleTop:栈顶复用模式。
  • singleTask:栈内复用模式。
  • singleInstance:单实例模式。

Standard模式

这是系统默认的模式,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已存在。被创建的实例的生命周期符合典型情况Activity的生命周期。它的onCreate、onStart、onResume都会被调用。一个任务栈中可以有多个实例,每个实例也可以属于不同的任务栈。这种模式下,谁启动这个Activity,这个Activity就会运行在启动它的Activity所在的栈中。如Activity A启动了Activity B(B是标准模式),B就会进入到A所在的栈中。

SingleTop模式

在这种模式下,若新Activity已经位于任务栈栈顶,那么此Activity就不会被重新创建,同时它的onNewIntent会被回调。通过此方法的参数我们可以取出当前请求的信息。需要注意的是,若这个Activity的实例存在,但不是在栈顶。则新Activity仍然会重建。若是ABCD这样,其中A位于栈底,D位于栈顶且启动模式为singleTop模式,则启动D并不会创建新的实例,栈内情况仍会是ABCD。但如果是ADBC这样,则重新启动D会创建新的实例,栈内情况会变为ADBCD。

SingleTask模式

这是一种单实例模式,在这种模式下,只要Activity在一个栈中存在,则多次启动此Activity都不会重新创建实例。和singleTop一样,系统会回调其onNewIntent方法。具体点,若一个singleTask的Activity A请求启动,系统首先会寻找是否存在A想要的任务栈,若不存在,重新创建一个任务栈之后创建A的实例后放到栈中。若存在A需要的任务栈,则看此任务栈中是否有A的实例存在,若有实例存在,系统就会把A调到栈顶并调用其onNewIntent方法。若实例不存在,就创建A的实例并将A压入栈中。

SingleInstance模式

这是一种加强的singleTask模式,它除了具有singleTask模式的所有特性外,还加强了一点,就是此模式的Activity只能单独地位于一个任务栈中。也就是说,比如A是singleInstance模式,当A启动,系统会专门为A创建一个新的任务栈,然后A独自在这个栈中,由于栈内复用特性,后续请求均不会创建新的Activity,除非这个任务栈被系统销毁了。

Activity间的数据传递

向请求启动的Activity传递数据

启动Activity我们用到了Intent,其实它也可以起到传递向启动的Activity中传递数据的作用。我们只需要通过putExtra方法将不同类型的数据添加到Intent中,然后在下一个Activity中获取到这个Intent,再从中获取我们需要的数据即可。

例如假设我们这里有个id需要传递给下一个Activity,就可以将id添加到intent中,再启动这个Activity:

然后,在下一个Activity中,获取到这个Intent,再从中获取数据即可。

Intent不仅可以传递常见的一些数据问题,还可以传递自己定义的序列化实体类对象。

传递序列化实体类对象

Serializable是序列化的意思,表示将一个对象转换成可储存或可传输的状态,对象进行Serializable序列化之后就可以通过Intent来进行Activity之间的传输了。

比如像下面这样Book类实现Serializable接口:

这里的serialVersionUID需要注意,它的作用是序列化和反序列化时保持版本的兼容性,如果未指定,运行时也会默认生成,在进行反序列化时只有数据和当前类的serialVersionUID相同是才能正常的反序列化。不指定serialVersionUID一般情况下也不会出问题,但是如果当前类发生了改变例如删掉了某个成员变量那么当前类的serialVersionUID也会出现改变,之后你对数据进行反序列化就会出现错误。

接下来就可以通过Intent来传递Book类的对象了。

然后,当我们获取的时候,就使用getSerializableExtra()方法来获取对象即可。

从请求启动的Activity中获取返回的数据

有时候,我们需要从请求启动的Activity中获取到一些数据(如处理结果之类的),这时可以通过startActivityForResult()方法来启动Activity,其有两个参数,前面的参数是启动的Intent,后面的参数是请求码,请求码只要是个唯一的值即可。

如果要在下一Activity返回时,只用new一个新的Intent,并向其中放入返回结果,最后调用setResult方法即可。

最后在请求启动的Activity中,通过重载onActivityResult方法,来做相应处理即可。

onActivityResult方法有三个参数,第一个参数requestCode,即我们在启动Activity时传入的请求码。第二个参数resultCode,即我们返回数据时传入的处理结果。第三个参数data,即携带了返回数据的Intent。


Android Developer in GDUT