Activity的生命周期

Android中的活动是可以层叠的,每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键会销毁最上面的活动,下面的一个活动就会重新显示出来。

其实Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称做返回栈(Back Stack)
栈是后进先出的一种数据结构,每当我们启动一个新的活动,它会返回栈中入栈,并处于栈顶。每当我们按下Back获知调用finish()方法销毁一个活动时,处于栈顶的活动会出栈,前一个活动就会重新处于栈顶的位置。系统总是会显示处于栈顶的活动给用户。
在这里插入图片描述

Activity的活动状态

每个活动在其声明周期中最多可能会有四种状态:

  • 运行状态
  • 暂停状态
  • 停止状态
  • 销毁状态

运行状态
放一个活动位于返回栈的栈顶是,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这回带来非常差的用户体验。

暂停状态
当一个活动不在处于栈顶位置,但仍然可见时,这时活动就进入了暂停状态,活动不在栈顶如何可见?这是因为并不是每一个互动都会沾满整个屏幕,比如对话框形式的活动只会占用屏幕中间的部分区域,很快用户就会在后面看到这种活动,处于暂停状态的活动仍然是完全存活的,系统也不愿意去回收这种活动(因为它还是可见的,回收可见的活动都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种活动。

停止状态
活动不再处于栈顶位置,并且完全不可见的时候,就进入了停滞状态,系统仍然会魏这种活动保存相应的状态和成员变量,但这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能会被系统回收。

销毁状态
当一个活动从返回栈中移除后,就变成了销毁状态,系统会倾向于回收处于这种状态的活动,从而保证手机的内存充足。

活动的生存周期

Activity类中定义了7个回调方法,覆盖了活动生命周期的每一个环节,下面就来一一介绍这7个 方法。

  • onCreate() :每个方法我们都重写了这个方法,它会在第一次创建的时候调用。我们应该在这个方法中完成活动的初始化操作,比如加载布局、绑定事件等。
  • onStart() 这个方法在活动由不可见变为可见的时候调用
  • onResume() 这个方案在活动准备好和用户进行交互的时候调用,此时的活动一定位于返回栈的栈顶,并且处于运行状态。
  • onPause() 这个方法在系统准备去启动或者回复另一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
  • onStop() 这个方法在活动完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法并不会执行。
  • onDestroy() 这个方法在活动被销毁之前调用,之后活动的状态将变成销毁状态。
  • onRestart() 这个方法在活动由停止状态变成运行状态之前调用,也就是活动被重新启动了。

以上7个方法中除了onRestart() 方法,其他都是两两相对的,从而又可以将活动分为3种生 存期。

-完整生存期。活动在onCreate() 方法和onDestroy() 方法之间所经历的,就是完整生 存期。一般情况下,一个活动会在onCreate() 方法中完成各种初始化操作,而 在onDestroy() 方法中完成释放内存的操作。

  • 可见生存期 。活动在onStart() 方法和onStop() 方法之间所经历的,就是可见生存 期。在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们 可以通过这两个方法,合理地管理那些对用户可见的资源。比如在onStart() 方法中对资 源进行加载,而在onStop() 方法中对资源进行释放,从而保证处于停止状态的活动不会 占用过多内存。
  • 前台生存期 。活动在onResume() 方法和onPause() 方法之间所经历的就是前台生存 期。在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的, 我们平时看到和接触最多的也就是这个状态下的活动。
    在这里插入图片描述

活动被回收了怎么办?
Activity中还提供了一个 onSaveInstanceState() 回调方法,这个 方法可以保证在活动被回收之前一定会被调用,因此我们可以通过这个方法来解决活动被回收 时临时数据得不到保存的问题。
onSaveInstanceState() 方法会携带一个Bundle 类型的参数,Bundle 提供了一系列的方 法用于保存数据,比如可以使用putString() 方法保存字符串,使用putInt() 方法保存整
型数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle 中取值,第二个参数是真正要保存的内容

@Override protected	void	onSaveInstanceState(Bundle	outState)	{
				super.onSaveInstanceState(outState);				
				String	tempData =	"Something you just typed";
				outState.putString("data_key",	tempData);
	 }

数据已经保存下来了,我们应该怎么恢复呢?
onCreate() 方法其实也有一个Bundle 类型的参数。这个参数在一般情况下都是null ,但是如果在活动被系统回收之前有通过onSaveInstanceState() 方法来保存数据的话, 这个参数就会带有之前所保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。

@Override protected	void	onCreate(Bundle	savedInstanceState)	{
				super.onCreate(savedInstanceState);				
				Log.d(TAG,	"onCreate");				
				setContentView(R.layout.activity_main);				
				if	(savedInstanceState	!=	null)	{								
						String	tempData	=	savedInstanceState.getString("data_key");								
						Log.d(TAG,	tempData);				
				}				
				...
	}

取出值之后再做相应的恢复操作就可以了,比如说将文本内容重新赋值到文本输入框上,这里 我们只是简单地打印一下。
生命周期描述
每个活动在生命周期中对多4种状态, 运行 暂停(对话框 ,后面的也是可见的只有在内存极低的时候系统不得已才会去回收这个东西,) 停止(不可见系统保存状态和成员变量,不可靠 内存不够就可能被干掉) 销毁
一般启动app:
oncreat(第一次被创建的时候,完成初始化操作,加载布局绑定事件)------onsatrt(不可见到可见)------onResume(准备好和用户进行交互调用,活动位于栈顶,) ------
onPause (在准备去启动其他活动,一般释放消耗CPU的以及保存一些关键数据,但是这个方法执行要快不然影响到后面的活动)------onStop(完全看不见的时候) ------onDestory(活动被销毁之前调用) ------ onRestart

onStart()和onResume()/onPause()和onStop()的区别?
onStart /onStop 从可见的角度回调的;而onResume/onPasue 从是否位于前台的角度回调的,而在实际应用中没什么区别。
onStart 可见不可点击
onResume 可见可点击;
onPause 可见不可点击(比如弹出对话框)
onStop 不可见

Activity A启动另一个Activity B会回调哪些方法?如果Activity B是完全透明呢?如果启动的是一个Dialog呢?
一、Activity A启动另一个Activity B回调那些方法

1、A界面==onCreate() ----->A界面==onStart()------> A界面==onResume() ---->A界面==onPause()

    ----> B界面==onCreate() ---->B界面==onStart()------->B界面==onResume()-----A界面==onStop()

   Activity B显示后 点击返回按钮 回调的方法

    B界面==onPause()------>A界面===onRestart()---->A界面==onStart()---->A界面==onResume()

    ----->B界面==onStop()------>B界面==onDestroy()

二、Activity A启动另一个Activity B 如果Activity B完全透明 会回调那些方法

1、A界面onCreate()—> A界面onStart()------> A界面onResume()---->A界面onPause()

   ----->B界面==onCreate()----> B界面==onStart()---->B界面==onResume()

Activity B显示后 点击返回按钮 回调的方法

B界面==onPause()----->A界面==onResume()---->B界面==onStop()----->B界面==onDestroy()

三、Activity A启动一个完全透明的Dialog 回调哪些方法
A界面启动一个dialog:如果是单纯的一个dialog,并不调用生命周期:A界面onCreate()—> A界面onStart()------> A界面==onResume()

如果启动的是一个以dialog形式展示的activity,同二。

谈谈onSaveInstanceState()方法?何时会调用?
Activity里的onSaveInstanceState()方法,虽然系统会自动调用它来保存Activity的一些数据,但当除它默认要保存的数据外,我们还要保存一些其他数据的时候, 我们就需要覆盖onSaveInstanceState()方法来保存Activity的附件信息。例如在播放视频过程中,横竖屏切换要保持当前播放时间进度,在默认情况下播放时间是不被自动保存的。
onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据
a.出现时机:异常 情况下Activity 重建,非用户主动去销毁
b.系统异常终止时,调用onSavaInstanceState来保存状态。该方法调用在onStop之前,但和onPause没有时序关系。
c.Activity被重新创建时,调用onRestoreInstanceState(该方法在onStart之后),并将onSavaInstanceState保存的Bundle对象作为参数传到onRestoreInstanceState与onCreate方法。

onSaveInstanceState()与onPause()的区别?
onPause():Activity的生命周期中的一个阶段,当Activity退出前台不再和用户进行交互时调用,可以用来保存一些持久化的数据。
onSaveInstanceState():帮助Activity保存临时的数据,比如各种UI状态。
联系与区别:两个方法都能够保存数据,一般onPause()用于保存持久化数据,比如向数据库写入数据,而onSaveInstanceState()用于保存临时数据。
当某个Activity正常结束生命周期,比如用户按下Back键调用onDestroy()方法时,onSaveInstanceState()方法不会被调用。其他情况下,比如按下Home键或者跳转到其他Activity,或者当某个Activity由于内存不足等原因被系统杀死时,就会调用onSaveInstanceState()方法。该方法是在onStop()方法之前被调用(与onPause()方法没有前后顺序),也就是说在Activity调用onStop()方法变得不可见之前就会调用onSaveInstanceState()保存Activity的UI信息,当该Activity被系统杀死后重新启动时,就会在onCreate()方法中取出onSaveInstanceState()保存的数据重新加载到UI上。

活动的启动模式

在实际项目中我们应该根据特定的需求为每个 活动指定恰当的启动模式。
启动模式一共有4种,分别是standard、singleTop、singleTask和 singleInstance
可以在AndroidManifest.xml中通过给 标签指定 android:launchMode 属性来选择启动模式。

standard
standard是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式
在standard模式(即默认情况)下,每当启动一 个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动,系统 不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。

@Override protected	void	onCreate(Bundle	savedInstanceState)	{				
		super.onCreate(savedInstanceState);				
		Log.d("FirstActivity",	this.toString());				
		setContentView(R.layout.first_layout);				
		Button	button1	=	(Button)	findViewById(R.id.button_1);				
		button1.setOnClickListener(new	View.OnClickListener()	{								
			@Override								
			public	void	onClick(View	v)	{												
				Intent	intent	=	new	Intent(FirstActivity.this,	FirstActivity.class);												
				startActivity(intent);								
				}	
			});
	}

在FirstActivity界面连续点击两次按钮,可以看到logcat中打印信息如图 2.33所示。在这里插入图片描述
从打印信息中我们就可以看出,每点击一次按钮就会创建出一个新的FirstActivity实例。此时返 回栈中也会存在3个FirstActivity的实例,因此你需要连按3次Back键才能退出程序
在这里插入图片描述
singleTop
当活动的启动模式指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。

<activity				
				android:name=".FirstActivity"				
				android:launchMode="singleTop"				
				android:label="This	is	FirstActivity">				
				<intent-filter>								
						<action	android:name="android.intent.action.MAIN"	/>
						<category	android:name="android.intent.category.LAUNCHER"	/>
				</intent-filter>
</activity>

之后不管你点击多少次按钮都不会再有新的打印信息出现,因为目前FirstActivity已经处于 返回栈的栈顶,每当想要再启动一个FirstActivity时都会直接使用栈顶的活动,因此FirstActivity 也只会有一个实例,仅按一次Back键就可以退出程序。
当FirstActivity并未处于栈顶位置时,这时再启动FirstActivity,还是会创建新的实例的。
在这里插入图片描述
singleTask
使用singleTop模式可以很好地解决重复创建栈顶活动的问题,但是正如你在上一节所看到的, 如果该活动并没有处于栈顶的位置,还是可能会创建多个活动实例的。
当活动的启动模式指定为singleTask,每次启动该活动时系统首先会在返回栈中检查是否存 在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统 出栈,如果没有发现就会创建一个新的活动实例。
修改AndroidManifest.xml中FirstActivity的启动模式:

<activity				
		android:name=".FirstActivity"				
		android:launchMode="singleTask"				
		android:label="This	is	FirstActivity">				
		<intent-filter>								
				<action	android:name="android.intent.action.MAIN"	/>								
				<category	android:name="android.intent.category.LAUNCHER"	/>				
		</intent-filter>
</activity>

然后再FirstActivity中添加onRestart()方法,并打印日志:

@Override 
protected	void	onRestart()	{
		super.onRestart();				
		Log.d("FirstActivity",	"onRestart");
	 }

最后在SecondActivity中添加onDestroy() 方法,并打印日志:

@Override 
protected	void	onDestroy()	{				
	super.onDestroy();				
	Log.d("SecondActivity",	"onDestroy");
 }

重新运行程序,在FirstActivity界面点击按钮进入到SecondActivity,然后在SecondActivity界 面点击按钮,又会重新进入到FirstActivity。
在这里插入图片描述
其实从打印信息中就可以明显看出了,在SecondActivity中启动FirstActivity时,会发现返回栈中 已经存在一个FirstActivity的实例,并且是在SecondActivity的下面,于是SecondActivity会从返回 栈中出栈,而FirstActivity重新成为了栈顶活动,因此FirstActivity的onRestart() 方法和 SecondActivity的onDestroy() 方法会得到执行。现在返回栈中应该只剩下一个FirstActivity的 实例了,按一下Back键就可以退出程序。
在这里插入图片描述
singleInstance
指定为singleInstance模式的活动会启用一个新的返回栈 来管理这个活动(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回 栈)
这么做的意义:
假设我们的程序中有一个活动是允许其他程 序调用的,如果我们想实现其他程序和我们的程序可以共享这个活动的实例,应该如何实现 呢?使用前面3种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个活 动在不同的返回栈中入栈时必然是创建了新的实例。而使用singleInstance模式就可以解决这个问 题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活 动,都共用的同一个返回栈,也就解决了共享活动实例的问题。
在这里插入图片描述
如何避免配置改变时Activity重建
技术点:Activity重建
思路:一种解决思路是设置配置文件中Activity的configChanges属性
参考回答:为了避免由于配置改变导致Activity重建,可在AndroidManifest.xml中对应的Activity中设置android:configChanges=“orientation|screenSize”。此时再次旋转屏幕时,该Activity不会被系统杀死和重建,只会调用onConfigurationChanged。因此,当配置程序需要响应配置改变,指定configChanges属性,重写onConfigurationChanged方法即可。

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如果不手动配置Activity configChanges属性,系统默认对Activity进行销毁重建操作。
API13以下,Activity configChanges属性中含有orientation即可避免Activity销毁重建。
API13及以上,Activity configChanges属性中同时含有orientation和screenSize即可避免Activity销毁重建。

优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?
内存不足时,Activity被回收了,进程也被杀死了。一般情况下进程是后台进程,当内存不足时,系统会杀死优先级低的后台进程,进程的Activity肯定就被回收了。
技术点:Activity重建
思路:可从Activity重建会被调用的方法出发
参考回答:优先级低的Activity在内存不足被回收后重新打开会引发Activity重建。Activity被重新创建时会调用onRestoreInstanceState(该方法在onStart之后),并将onSavaInstanceState保存的Bundle对象作为参数传到onRestoreInstanceState与onCreate方法。因此可通过onRestoreInstanceState(Bundle savedInstanceState)和onCreate((Bundle savedInstanceState)来判断Activity是否被重建,并取出数据进行恢复。但需要注意的是,在onCreate取出数据时一定要先判断savedInstanceState是否为空。另外,谷歌更推荐使用onRestoreInstanceState进行数据恢复。

说一下Activity四种启动模式?
技术点:Activity启动模式
思路:分条解释四个启动模式的特点

  • standard标准模式:每次启动一个Activity就会创建一个新的实例
  • singleTop栈顶复用模式:如果新的Activity已经位于任务栈的栈顶,就不会被重建,并回调onNewIntent(Intent)方法
  • singleTask栈内复用模式:只要该Activity在一个任务栈中存在,都不会重新创建,并回调onNewIntent(Intent)方法。如果不存在,系统会先寻找是否存在需要的栈,如果不存在该栈,就创建一个任务栈,并把Activity放进去;如果存在,就会创建到已经存在的栈中。
  • singleInstance单实例模式:具有此模式的Activity只能单独位于一个任务栈中,且此任务栈中只有唯一一个实例。

谈谈singleTop和singleTask的区别和应用场景
技术点:Activity启动模式
思路:可先解释两个启动模式的含义(见上一个问题),再总结不同点,最后给出应用实例
参考回答:singleTop和singleTask的含义分别是…,可见两者大致区别有:
singleTop:同个Activity实例在栈中可以有多个,即可能重复创建;该模式的Activity会默认进入启动它所属的任务栈,即不会引起任务栈的变更;为防止快速点击时多次startActivity,可以将目标Activity设置为singleTop
singleTask:同个Activity实例在栈中只有一个,即不存在重复创建;可通过android:taskAffinity设定该Activity需要的任务栈,即可能会引起任务栈的变更;常用于主页和登陆页

onNewIntent()调用时机
技术点:Activity启动模式
参考回答:启动模式为singleTop或singleTask的Activity在以下情况会回调onNewIntent():
singleTop:如果新Activity已经位于任务栈的栈顶,就不会重新创建,并回调 onNewIntent(intent) 方法
singleTask:只要该Activity在一个任务栈中存在,都不会重新创建,并回调 onNewIntent(intent) 方法。
一个Activity在第一次启动的时候,生命周期不会执行该方法,当再一起想要启动Activity的时候就会执行onNewIntent()---->onResart()------>onStart()----->onResume(). 如果android系统由于内存不足把已存在Activity释放掉了,那么再次调用的时候会重新启动Activity即执行onCreate()---->onStart()---->onResume()等。

了解哪些Activity启动模式的标记位
技术点:Activity启动模式
参考回答:常见的两个标记为:
FLAG_ACTIVITY_SINGLE_TOP:对应singleTop启动模式
FLAG_ACTIVITY_NEW_TASK :对应singleTask模式
引申:可再谈谈singleTop和singleTask具体效果

如何启动其他应用的Activity
技术点:Activity启动、IntentFilter匹配
思路:可从隐式Intent角度出发
参考回答:在保证有权限访问的情况下,通过隐式Intent进行目标Activity的IntentFilter匹配,原则是:
一个intent只有同时匹配某个Activity的intent-filter中的action、category、data才算完全匹配,才能启动该Activity。
一个Activity可以有多个 intent-filter,一个 intent只要成功匹配任意一组 intent-filter,就可以启动该Activity。
引申:如有必要可展开说明action、category、data的具体匹配规则

Activity的启动过程
技术点:Activity启动、ActivityManagerServie、ApplicationThread
思路:可大致介绍Activity启动过程涉及到的类,尤其是ActivityManagerServie、ApplicationThread从中发挥的作用。详见要点提炼|开发艺术之四大组件
参考回答:调用startActivity()后经过重重方法会转移到ActivityManagerService的startActivity(),并通过一个IPC回到ActivityThread的内部类ApplicationThread中,并调用其scheduleLaunchActivity()将启动Activity的消息发送并交由Handler H处理。Handler H对消息的处理会调用handleLaunchActivity()->performLaunchActivity()得以完成Activity对象的创建和启动。
startActivity–>ActivityManagerService
ActivityManagerService–>ApplicationThread
ApplicationThread–>Activity

引申:由于ActivityManagerService是一个Binder对象,可引申谈谈Binder机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值