戏说Android四大组件之Activity
戏说江湖静如水,游荡江湖才有情。我就是江湖中的一个戏子。
俗话说,入行先入门。作为一名android学习者,四大组件是android中的核心组件,岂有不学之理。然而,本人才疏学浅,叙述略有不当之处,敬请谅解。
Activity作为android中经常用到的组件。通常用来展示界面,承载内容之用。Activity相当于一个幕布,后台有着各种各样的控件,如TextView,EditText,ListView等,当然还有针对这些控件以及控件展示的数据进行处理的各种各样的操作。当然作为一个幕布,当然有自己展示的一套机制。在Activity中,这套机制就叫做生命周期。
生命周期
Activity有七个生命周期,分别是onCreate,onStart,onResume,onPause,onStop,onDestory,onRestart。具体的生命周期图网上很多,这里我就不附图了。在下附一个我自己总结的表格仅供参考(该表格是在默认的条件下)。
过程 | 调用函数 |
---|---|
第一次启动Activity | onCreate,onStart,onResume |
重新启动Activity | onRestart,onStart,onResume |
当前Activity被其他Activity或Dialog覆盖或锁屏时 | onPause |
当前Activity由覆盖状态转为前台或解锁时 | onResume |
用户退出当前Activity | onPause,onStop,onDestroy |
用户点击Home键,电源键 | onPause,onStop |
用户旋转屏幕 | 先退出,再启动Activity。onPause,onStop,onDestory,onCreate,onStart,onResume |
当然上述的生命周期在不同的条件下也会出现例外,这就和Activity栈有关。那么Activity栈又是个什么玩意呢?有的同学在学数据结构的时候可能已经学过堆栈了,对,这个和堆栈其实差不多,只不过在这个栈中存放的对象是各种Activity。其和堆栈的特性差不多,也是后进先出
,并且显示的是当前栈顶的Activity。
一个应用管理一个属于自己的Activity栈,
Activity栈
Activity栈在什么时候体现和设置呢?我们知道在Android项目中,有一个配置文件叫AndroidMainfest.xml文件,该文件可以设置权限,声明Activity。在声明Activity的时候就可以设置其Activity的属性,来控制启动Activity时,Activity栈需要做的活动。
首先启动Activity的时候,假若系统中有很多个Activity栈,那么该Activity栈怎么知道要跳到哪个栈呢?这个其实与Activity栈的一个属性有关,就是taskAffinity有关,当然这个属性一般都是默认好的,不需要自己去设置,当然设置了不同的属性会带来不同的效果。
taskAffinity
taskAffinity是application的一个默认属性,用来标示Activity栈,Affinity是亲和力的意思,也就是说当taskAffinity相同的时候,也就是这些Activity具有亲和力,那么他们就会被压入同一个Activity栈。当Activity启动的时候会去遍历所有Activity栈的taskAffinity,如果有相同的,则压入该栈,如果没有,则新建一个Activity栈。当然也有例外,这就和Activity的启动模式有关了。
Activity启动模式
启动模式其实就是说Activity在启动的时候,Activity栈进行的操作,是用新的实例压入栈中,还是用原来的就已经存在的实例。在Activity的launchMode属性进行设置。
//standard,singleTop,singleTask,singleInstance
//其中standard是系统默认的,可以不用进行设置
android:launchMode="singleTop"
Activity的启动模式有四种,总结如下表:
启动模式 | 实际操作 |
---|---|
standard | 启动Activity时,直接创建新的实例添加到Activity栈中 |
singleTop | 启动Activity时,如果在Activity栈的栈顶已存在该实例,则直接使用该实例,如果该Activity的实例不在栈顶,那也会创建新的实例添加到Activity栈中 |
singleTask | 启动Activity时,如果在Activity栈中含有该Activity的实例,那么弹出该Activity上面的所有Activity实例,显示该Activity。 |
singleInstance | 启动Activity时,判断该Activity是否存在,如果不存在,则新建一个Activity栈,将之存放在该栈顶。如果存在,则使用该实例。 |
|启动模式|在栈顶|其他Activity动作|目标Activity动作|
|--|--|--|
|standard||onPause,onStop|onCreate,onStart,onResume|
|singleTop|是|无|onPause,onResume|
|singleTask|否|onPause,onStop,onDestory|onRestart,onStart,onResume|
是否觉得上述表格有其他几种情况没有描述,其实其他几种情况是重复的,如下表所示
启动模式 | 在栈顶 | 类似启动模式 | 在栈顶 |
---|---|---|---|
singleTop | 否 | standard | 无所谓 |
singleTask | 是 | singleTop | 是 |
singleInstance | 否 | standard | 否 |
singleInstance | 是 | singleTop | 是 |
由于singleInstance是新建一个Activity栈,与当前Activity栈无关,是独享的。其他的Activity不会进入到该Activity栈中。
启动模式会影响Activity栈的操作。同样的Activity也有相关的Task属性可以设置,以及在跳转的时候设置Intent的Flag也有这样的效果,让我们来看一下。
Activity与Task相关的属性
在AndroidMainfest.xml文件中的Activity中设置以下属性就就可以得到以下的效果。
属性 | 作用 |
---|---|
android:allowTaskReparenting | 标记当前Activity实例在当前应用退居后台,启动相同taskAffinity的应用,是否能移动到该应用的Activity栈中 |
android:alwaysRetainTaskState | 标记当前应用的Activity栈是否保持原来的状态。该属性只针对于根Activity,可以用来防止后台程序长时间不启动导致系统自动回收 |
android:clearTaskOnLaunch | 用来标记是否在启动该Activity时,清除除根目录的其他Activity |
android:finishOnTaskLaunch | 当用户重新回到该Activity时,会销毁该Activity。 |
Intent Flag与Task相关的属性
在Intent跳转的时候可以设置相应的flag值,
intent.setFlags(flags);
以到达Activity栈相关的操作,总结如下表
属性 | 作用 |
---|---|
FLAG_ACTIVITY_MULTIPLE_TASK | 创建一个新的Activity栈,并在其中启动Activity |
FLAG_ACTIVITY_NO_HISTORY | 新启动的Activity不会保存在原有的Activity栈,并且不会调用onActivityResult函数 |
FLAG_ACTIVITY_SINGLE_TOP | 相当于singleTop启动模式 |
FLAG_ACTIVITY_NEW_TASK | 相当于singleInstance启动模式 |
FLAG_ACTIVITY_CLEAR_TOP | 创建一个新的实例代替旧的实例并清除该实例以上的所有实例 |
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | 新的Activity不会放在近期启动Activity列表中 |
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | 该Activity要么启动一个新的Activity栈,要么在已存在的Activity栈的栈顶,这个Activity栈运行在前台。 |
FLAG_ACTIVITY_NEW_DOCUMENT | 一旦该Activity被清除,那么该Activity所在栈上的所有Activity会被移除 |
FLAG_ACTIVITY_CLEAR_TASK | 当该Activity启动之前,所有与该Activity相关联的Activity栈将会清除,该Activity成为另外一个空栈的根Activity |
FLAG_ACTIVITY_LAUNCH_ADJACENT | 该flag只在分屏多窗口模式使用,配合FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_MULTIPLE_TASK |
当然Intent还有其他的flag,在这里我就不一一叙述了。
总结
- Activity栈就是堆栈的一种,里面存放着Activity的实例,并且显示栈顶的Activity实例。
- Activity栈通过affinity值唯一标识
- Activity启动要么创建新的实例,要么使用已有的实例。如果是使用已有实例通过进出栈来保证该实例在栈顶
- Activity结束时要么将该该Activity放在近期启动列表中,要么不放。可以通过相关属性防止Activity被系统回收。
Activity其他常见属性
configChanges
该属性是当手机相关属性发生变化时,回调onConfigurationChanged函数,一般用来避免因为横竖屏切换导致Activity生命周期的调用。
如果没有设置该属性,在旋转屏幕的时候,会调用一次Activity的销毁和启动。
设置Activity属性
android:configChanges="orientation|screenSize"
如果手机再次旋转屏幕时,会回调onConfigurationChanged,这个时候可以在该方法中进行相应的操作。
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
}
}
screenOrientation
如果不希望手机旋转可以设置该属性,强制手机的方向
android:screenOrientation="portrait"//portrait竖屏|landscape横屏
windowSoftInputMode
该属性用来设置该Activity获得焦点时,软键盘的显示状态以及软件盘怎么显示。
android:windowSoftInputMode="stateHidden|adjustPan"
也可以在Activity中通过代码设置
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN|WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
Activity暂时就讲这么多了,讲的不好大家别见怪啊!