note_32:总结activity生命周期

24 篇文章 0 订阅

总结activity生命周期


参考:



1. activity生命周期

activity在它的生命周期里面最多可能会有4种状态:运行状态暂停状态停止状态销毁状态。最核心的回调函数有6个:onCreate()onStart()onResume()onPause()onStop()onDestroy()

图片来自安卓开发国内镜像
图片来自安卓开发国内镜像

(1) 运行状态

运行状态,也就是用户可见并且可以跟activity进行交互的状态。
涉及到的三个比较核心的回调函数onCreate()onStart()onResume()

当activity创建的时候,先执行onCreate(),此时activity处于created状态,但是这个状态很短暂。马上就会执行onStart(),进入started状态,同样,这个状态也非常短暂。马上就会执行onResume,进入resumed状态,并且如果没有别的事情发生的话,activity将一直处于这个状态。

  • onCreate()
    activity创建或者首次启动的时候会调用的方法。在这个方法里面可以进行一些基本的初始化操作,例如定义UI、实例化类成员变量。但是只能做基本的初始化工作,不要做太耗时间的初始化工作,不然界面会半天加载不出来,要是超时严重的话还有可能停止运行。如果要读一大批数据,不要直接在onCreate()里面做,可以考虑开线程和添加handler,避免把主界面卡死。

    setContentView()
    onCreate() 里面调用setContentView() 就是为了绑定当前activity的View,否则在初始化界面的时候就不能直接使用findViewById(),而是要写完整的view.findViewById()

  • onStart()
    activity由不可见变为可见的时候调用。

  • onResume()
    系统调用完onStart()之后会迅速调用onResume(),使得activity停留在Resumed状态(如果没有其他因素干扰的话)。这时activity已经准备好跟用户进行交互。

(2) 暂停状态

暂停状态,activity处于 部分可见(半透明) 的状态,但是用户不能跟activity交互。例如,刚好从activityA切换到activityB时,在切换的那一瞬间activityA会进入onPause()。又比如,刚好有一个对话框(Dialog或者DialogFragment)从activityA弹出来,这时用户可以看到activityA,但是由于它的表面有一个对话框,所以用户没办法直接对activityA进行操作,除非把对话框关掉。

暂停状态涉及到一个回调函数onPause()

  • onPause()
    系统准备去启动或者恢复另一个activity时调用,意味着用户准备离开当前这个activity,并且马上要进入Stopped状态。

    通常,应该在onPause()里面做下面的事情:

      (1)停止动画或者其他正在运行的操作,因为这些都会导致CPU资源浪费。
      (2)提交用户离开时希望保存的数据,例如邮件草稿。
      (3)释放系统资源,例如BroadcastReceiver、照相机,或者是任何会影响到电量的资源。
    

    需要注意的地方是:
    虽然(2)提到可以保存数据,但是必须明确的是在onPause()里面保存的数据只是针对那些必须及时保存的数据,例如邮件草稿。不应该把全部保存数据的操作放到onPause()里面,尤其是写入数据库或者本地文件这种要对数据进行永久存储的操作。我们应该避免onPause()里面进行高强度消耗CPU的操作,例如前面说的写入数据库或文件,原因跟在onCreate()里面读大量数据差不多,会卡界面。因为onPause()就是切换activity,如果在切换过程中执行高强度消耗CPU的操作,当前这个要暂停的activity可能会等上一段时间才能暂停,而那个准备要切换的activity又切换不出来,结果就是界面加载很久都看不到。

(3) 停止状态

停止状态跟暂停状态最大的不同是,停止状态是UI完全不可见的,并且用户的焦点转移到了另一个activity上。

停止状态涉及到的回调函数是onStop()

  • onStop()
    当activity调用onStop()时,activity不再可见,并且应该释放所有不再需要的资源(除了一部分线程以外)。不应该在onPause()做高强度消耗CPU的操作,应该在onStop()里面进行。一旦activity停止,系统会在需要内存空间的时候销毁它的实例(和栈结构有关)。极端情况下,系统会直接杀死整个APP进程,而且不执行onDestroy()。这也是为什么要在onStop()释放资源,否则极有可能出现内存泄漏

恢复和重启

恢复activity就是从onPause()回到onResume()
在这里插入图片描述
重启activity就是从onStop()onRestart()再到onStart()最后到onResume()
在这里插入图片描述

onPause()对应onResume()onStop()对应onStop()

系统每次调用onPause()时,activity都处于前台,包括第一次创建的时候。所以,应该实现onResume()来初始化那些在onPause()里面释放掉的组件,并执行那些activity每次进入Resumed状态都需要的初始化动作(例如开始动画与初始化那些只有在获取用户焦点时才需要的组件)。

当activity从Stopped状态回到前台时,它会调用onRestart(),然后再调用onStart()。当activity从Stopped状态恢复时,必须执行一些特殊的恢复工作来重新实例化那些被清楚的资源。由于使用onRestart()来做恢复状态不太常见,所以应该在onStart()里面重新把那些清除掉的资源重新创建出来。


(4) 销毁状态

销毁状态是activity的最后一个状态,意味着activity被彻底移除。

跟销毁状态直接相关的回调函数是onDestroy()

  • onDestroy()
    事实上,onDestroy()不算是很常用的方法,至少跟前面的五个回调方法相比是这样的。当app从一个activity跳到另一个activity并不会执行onDestroy(),而是执行onStop(),除非主动调用了finish()或者点击了导航栏上的返回键(系统调用onBackPressed())又或者屏幕旋转了(系统先执行onDestroy()onCreate()),又或者是当前app占用过多内存被系统强行杀死才会进入调用onDestroy()

    但这并不意味着onDestroy()不需要实现。如果当前activity开启了线程或者当前app开启了service的话,就要在onDestroy()的时候关掉,不然会内存泄漏。


重新创建

当系统因为某个app占用过多资源而强行执行onDestroy()的时候,系统会把activity的记录保存下来,这些被系统用来恢复之前状态而保存下来的数据叫做instance state,它的保存形式是放在Bundle对象中的键-值对

在这里插入图片描述

  • onSaveInstanceState()
    当用户离开activity的时候,系统会调用这个方法。当系统调用这个函数时,系统会在activity被异常destroy时传递Bundle对象,这样我们就可以增加额外的信息到Bundle并保存到系统中,用于activity的重建。

通常来说,跳转到其他的activity或者是点击HOME都会导致当前的activity执行onSaveInstanceState(),因为这种情况下的activity都是有可能会被destroy并且是需要保存状态以便后续恢复使用的。而从跳转的activity点击BACK回到前一个activity时,因为跳转前的activity执行的是退栈操作(不可能存在需要重建的操作),所以这种情况下系统不会执行onSaveInstanceState

返回栈

android是使用任务(task)来管理activity的,一个任务就是一组存放在栈里的activity的集合,这个栈也被称作返回栈(backstack)。在默认情况下,每当启动了一个新的activity,它就会在返回栈中入栈,处于栈顶。如果用户按HOME键或者BACK键,处于栈顶的activity会出栈(被销毁),而前一个入栈的activity就会处在栈顶。那些有机会恢复状态的activity都是没有出栈的,只是暂时不处于栈顶而已,过后还是有可能处在栈顶的,所以系统才会执行onSaveInstanceState()

正常出栈的activity根本没必要保存现场,因为它的移除是永久的,如果要跑这个activity,就是重新入栈。对于异常出栈的activity,系统会自动保存它的状态。

  • onRestoreInstanceState()
    若系统在activity被destroy之后想要重新创建这个activity实例时,之前的Bundle对象会被传递到activity的onRestoreInstanceState()方法和onCreate()方法中。onRestoreInstanceState()会在onStart()方法之后执行,可以用来恢复数据。系统仅仅会在存在需要回复的状态信息时下回调用onRestoreInstanceState(),因此不需要像在onCreate()里面那样检查Bundle是否为null

ActivityLifecycleCallbacks

安卓官方提供了一个ActivityLifecycleCallbacks的接口,可以通过这个接口获取当前app里面所有的activity的生命周期。实现这个接口里面的一部分方法,并且把app注册到这个接口上就可以使用了。


2. 启动模式

activity有四种启动模式:standardsingleTopsingleTasksingleInstance

(1) standard

标准模式是默认的启动模式,每次启动一个activity就会创建一个新的activity实例,不管栈里面有没有这个实例。

每次启动activity时都是创建一个新的实例,所以涉及的回调函数就是:onCreate()onStart()onResume()onPause()onStop()onDestroy()

(2) singleTask

栈内复用模式,也可以叫栈内单例模式。栈内只有该activity的实例只有一个。如果栈内已经存在这个activity,而这个activity不在栈顶,这时要启动这个activity,系统会直接把栈内这个activity上面的别的实例出栈,直接把这个activity变成栈顶。

例如现在栈内的情况是:A(栈底)、B、C、D、E(栈顶)。
现在要启动C,假设C的启动模式是singleTask,那么系统就会把D和E直接出栈,此时栈内情况变成:A(栈底)、B、C(栈顶)。

由于每一次启动activity时会检查栈内有没有这个activity的实例,所以如果没有进行栈内复用的时候,就相当于走standard模式,系统会调用6个回调函数。如果进行了栈内复用的话,系统调用的回调函数是:onNewIntent()onResume()onPause()onStop()onDestroy(),系统不会执行onCreate()onStart()

(3) singleTop

栈顶复用模式。如果要创建的activity的实例已经处在栈顶,那么系统就不会创建这个activity的实例,会直接使用当前处于栈顶的这个实例。如果要创建的activity的实例没有处在栈顶,那么系统就会像标准模式一样创建这个activity的实例。

由于每一次启动activity时会检查栈顶,如果栈顶不能复用的话就相当于走了一次standard模式,所以还是涉及那6个回调函数。但是如果栈顶复用了的话,涉及到的回调函数就会变成onNewIntent()onResume()onPause()onStop()onDestroy(),系统不会执行onCreate()onStart()

(4) singleInstance

全局单例模式,也叫堆内单例模式。整个操作系统里面只有一个实例存在。


onNewIntent(Intent intent)丢失Extras

主要是因为传进来的那个Intent走完super.onNewIntent()之后可能会莫名其妙地丢了,而且事实上每分每秒都有很多不知道从哪里来的Intent进入这个onNewIntent()的函数里,所以才说不能直接getIntent()或者直接拿参数列表里面那个intent。网上普遍推荐的方法是在super.onNewIntent()之后再使用setIntent()来更新在这个方法里面的Intent

如果是使用PendingIntent来启动intent的话,就不需要setIntent()了。可以直接把PendingIntent的最后一个参数flag设置为PendingIntent.FLAG_UPDATE_CURRENT,就是把当前这个PendingIntent的数据更新为当前最新的数据。因为系统里面也是有无数个PendingIntent,然而系统觉得它们是一个东西,所以如果flag参数设置为0的话,那么这个PendingIntent所携带的extras百分之一百会丢失。


3. 应用场景

Android-Activity四种启动模式第二点的表格。
Android:图解四种启动模式 及 实际应用场景解说第二点。


4. activity的flag

Intent.addFlags() 启动Activity的20种flags全解析


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值