Activity常用配置属性介绍:
android:exported=“true/false” : 指定该Activity是否允许被其他应用调用。true表示可以被其他应用调用。
android:launchMode=“singleTask” : 指定Activity的启动模式(加载模式),支持standard(默认)、singleTop、singleTask、singleInstance。
android:taskAffinity=“taskname” : 指定Activity关联的任务栈。属性值为字符串,且中间必须含有包名分隔符“.”。
与singleTask启动模式配合使用时,表示指定此Activity实例所在的Task栈。如果taskname的名字同包名,则相当于没有设置taskAffinity属性(因为启动Activity默认task名称就是包名);如果taskname指定的Task栈不存在则会新创建一个Task栈;如果taskname指定的Task栈存在,则复用此Task栈。
taskAffinity也可以跟singleInstance模式配合使用,用于指定该模式启动的Activity所在的Task栈的名字。
另外taskAffinity属性还可以跟android:allowTaskReparenting属性配合使用。效果为:当应用A启动了应用B的某个Activity后,如果这个Activity的allowTaskReparenting属性为true,那么当应用B被启动后,此Activity会直接从应用A的Task栈转移到应用B的Task栈中。
: 指定该Activity可响应的Intent
启动Activity的两种方法:
startActivity(Intent intent)
: 通过intent指定要启动的Activity。
startActivityForResult(Intent intent, int requestCode)
: 以指定的请求码启动Activity,requestCode用于标识请求来源。并且当前Activity将会获取到新启动Activity返回的结果(通过重写onActivityResult(int requestCode, int resultCode, Intent data)来获取)
关闭Activity:
finish()
: 关闭当前Activity
finishActivity(int requestCode)
: 结束以startActivityForResult方法启动的Activity。
通过Intent + Bundle在Activity之间交换数据
Intent作为Activity之间传递数据的媒介,数据则是封装到Bundle中。通过将Bundle绑定到Intent,实现Activity之间的数据交互。
在Activity中可以通过getIntent方法获取启动时传入的intent对象,从而可以获取intent中携带的数据。
Intent提供大量put、get方法存取数据,这些方法都是通过将数据保存到Intent中Bundle类型的mExtras变量中实现的。
putExtra(String name, Xxx value) : Xxx可以表示基本数据类型、String、Parcelable等类型
putExtra(String name, Xxx[] value)
putExtra(String name, Bundle value)
putExtra(String name, Serializable value)
putExtras(Bundle extras)
putStringArrayListExtra(String name, ArrayList value)
putIntegerArrayListExtra(String name, ArrayList value)
getXxxExtra(String name, Xxx defaultValue) : Parcelable类型没有默认值参数
getXxxArrayExtra(String name)
getBundleExtra(String name)
getStringArrayListExtra(String name)
getIntegerArrayListExtra(String name)
startActivityForResult启动其他Activity并返回结果
之所以存在startActivityForResult这个方法,从其他Activity中返回数据到当前Activity。是因为存在如下情形:用户在当前界面需要从某个列表中获取数据,而这个列表比较复杂,不适合在当前界面显示,于是可以另外启动一个界面用户显示列表,但是在这个列表界面选择的数据是需要交给之前用户所在的界面处理的,所以提供了startActivityForResult方法实现启动其他界面获取数据并返回数据到当前界面的功能。其他界面返回数据通过setResult方法实现。而当前界面是不知道其他界面什么时候返回数据的,所以就需要一个监听回调方法来捕获数据:onActivityResult。
startActivityForResult(Intent intent, int requestCode)
: 参数intent用于指定启动哪个activity,requestCode传给onActivityResult,用于区分当前Activity是启动的哪个Activity。因为当前Activity可能会多次调startActivityForResult启动不同的界面,所以这个requestCode就用于区分每次启动其他界面的请求,从而在onActivityResult中判断是哪个界面返回了数据。
setResult(int resultCode, Intent data)
: 通过startActivityForResult被启动的其他Activity通过setResult方法返回数据。参数resultCode传给onActivityResult做形参,用于确定匹配resultCode的这次onActivityResult方法的回调,就是携带了返回结果数据的回调。
data中保存了返回的结果数据。data参数在其他Activity中一般可通过getIntent方法,直接取用startActivityForResult传过来的intent对象表示,向此intent中存入结果数据。
setResult(int resultCode)
: 当不需要返回结果数据时,可用此方法。
onActivityResult(int requestCode, int resultCode, Intent data)
: 当通过startActivityForResult方法启动的其他界面退出时,会回调此方法。requestCode用于判断是哪个界面返回了数据;resultCode用于判断此次方法回调是否携带了返回结果。data用于携带返回结果。
onCreate
onRestart
onStart
onResume
onPause
onStop
onDestory
几种具体情况下Activity生命周期方法的回调
1. 资源相关的系统配置发生改变导致Activity被杀死并重新创建
当应用程序启动时,系统会根据当前设备的情况去res目录下匹配相应设备的资源文件夹中加载合适的Resource资源。比如横屏手机和竖屏手机会拿到两张不同的图片(设定了landscape或portrait状态下的图片)。
如果当前Activity处于竖屏状态,此时旋转屏幕,由于系统配置发生了改变,默认情况下,Activity会被销毁并且重新创建(可以给Activity指定configChanges属性,阻止系统重新创建Activity)。Activity被销毁并且重新创建的生命周期如上图所示。
在onSaveInstanceState和onRestoreInstanceState方法中,系统自动为我们做了一些恢复工作。比如当Activity在异常情况下需要重新创建时,系统会默认保存当前Activity的视图结构,并在Activity重启后恢复这些View相关的数据。如文本框中用户输入的数据,ListView滚动的位置等。
每个View也都有onSaveInstanceState和onRestoreInstanceState方法,查看它们的具体实现,就能知道系统会自动为每个View恢复哪些数据。
关于保存和恢复View层次结构,系统的工作流程:
上述流程是一种典型的委托思想,上层委托下层,父容器委托子元素去处理事件。这种思想在Android中有很多应用,如View的绘制过程,事件分发等。
2. 资源内存不足导致低优先级的Activity被杀死
Activity按照优先级从高到低,可以分为三种:
当系统内存不足时,系统会按照上述优先级去杀死目标Activity所在的进程,并在后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据。
如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死。因此,一些后台工作不适合脱离四大组件而独立运行在后台中。比较好的方法是将后台工作放到Service中,从而保证进程有一定的优先级,这样就不会轻易被系统杀死。
3. 通过configChanges属性,阻止系统重新创建Activity
当系统配置发生改变时,Activity会被重新创建。如果不想Activity因为某项系统配置改变而重新创建,可以通过给Activity指定configChanges属性实现。
属性值项目 | 含义 |
---|---|
mcc | mcc代码发生了改变。(mcc是指SIM卡唯一标识IMSI中的国家代码,中国为460) |
mnc | mnc代码发生改变。(mnc是指SIM唯一标识IMSI中的运营商代码,移动TD为00,联通01,电信03) |
locale | 设备的本地位置发生了改变,一般指切换了系统语言 |
keyboard | 键盘类型发生了改变,比如用户使用了外插键盘 |
keyboardHidden | 键盘的可访问性发生了改变,比如用户调出了键盘 |
screenLayout | 屏幕布局发生了改变,很可能是用户激活了另外一个显示设备 |
fontScale | 系统字体缩放比例发生了改变,比如用户选择了一个新字号 |
uiMode | 用户界面模式发生了改变,比如是否开启了夜间模式(API8新添加) |
orientation | 屏幕方向发生了改变,比如旋转了手机屏幕 |
screenSize | 屏幕尺寸信息发生了改变。当旋转屏幕时,屏幕尺寸会发生改变。当编译选项中的minSdkVersion和targetSdkVerison均低于13时,此选项不会导致Activity重启,否则会导致Activity重启(API13新添加) |
smallestScreenSize | 设备物理屏幕尺寸发生了改变。此项目和屏幕方向无关,仅仅表示在实际的物理屏幕尺寸改变时发生,比如用户切换了外部的显示设备。当minSdkVersion和targetSDKVersion均低于13时不会导致Activity重启,否则会。(API 13新添加) |
上表是configChanges属性的部分属性值及其含义。如果没有在Activity的configChanges属性中指定某个配置项目时,那么当该配置项目发生改变后就会导致Activity销毁并重新创建,执行onSaveInstanceState和onRestoreInstanceState方法。如果在configChanges属性中指定了某个配置项目,则当该配置项目发生改变时,会另外调用Activity的onConfigurationChanged方法,并且Activity也不会被销毁并重新创建。
configChanges属性在AndroidManifest.xml中为Activity指定。如android:configChanges="orientation|screenSize"
。使用"|"可以同时指定多个值。
一、 standard模式(标准模式)
二、 singleTop模式(栈顶复用模式)
三、 singleTask模式(栈内复用模式)
采用这种加载模式的Activity,在同一个Task栈内只有一个实例,当系统采用singleTask模式启动Activity时,在启动该Activity所需的Task栈存在的条件下,有如下三种情况:
上面说的Activity所需的Task栈,默认情况下是以应用包名命名的Task栈。如果配置Activity时指定了android:taskAffinity属性,并赋值为不同于包名的其他名称taskname,则当该taskname表示的Task栈不存在时,系统会先创建一个名为taskname的Task栈,然后再把activity实例添加到栈顶。
当Activity所需的Task栈存在时,但是此Task栈是一个后台Task栈,那么启动这个Activity时,会先把它所需的Task栈调到前台,然后再根据上述的三种情况将该Activity添加到此Task栈中。
四、 singleInstance模式(单实例模式)
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
具有此标记位的Activity,当它启动时,如果task栈中已存在此Activity实例,那么在task中,所有位于此Activity实例上面的Activity都要出栈。
FLAG_ACTIVITY_SINGLE_TOP
当task中存在目标Activity实例并且位于栈的顶端时,不再创建一个新的,直接利用这个实例。与Activity启动模式中的singleTop效果相同。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
具有这个标记的Activity不会出现在历史Activity列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity时,这个标记比较有用。它等同于在XML中指定Activity的属性android:excludeFromRecents=“true”
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
如果一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的所有Activity都会在task重置时被清除出task(前提:FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)。当我们将一个后台的task重新回到前台时,系统会在特定情况下为这个动作附带一个FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,意味着必要时重置task,这时FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET就会生效。
这个标记对于应用存在分割点的情况会非常有用。比如我们在应用主界面要选择一个图片,然后我们启动了图片浏览界面,但是把这个应用从后台恢复到前台时,为了避免让用户感到困惑,我们希望用户仍然看到主界面,而不是图片浏览界面,这个时候我们就要在转到图片浏览界面时的Intent中加入此标记。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Intent.ACTION_MAIN="android.intent.action.MAIN"
, Intent.ACTION_VIEW="android.intent.action.VIEW"
。另外我们也可以自己定义action。Intent.CATEGORY_LAUNCHER="android.intent.category.LAUNCHER"
,Intent.CATEGORY_DEFAULT = "android.intent.category.DEFAULT"
。 另外我们也可以自定义category。过滤规则中data的定义:
data由两部分组成:mimeType和URI
URI的结构:
,其中
*
的完整路径信息。*
表示0个或多个任意字符。mimeType指媒体类型,如image/jpeg、text/plain、video/*等,可以表示图片、文本、音视频等媒体格式。
data的匹配规则
IntentFilter的匹配规则对于Service和BroadcastReceiver也是同样的道理。系统对于Service的建议是尽量使用显示调用的方式来启动服务。
可以通过PackageManager提供的resolveActivity或Intent的resolveActivity判断是否存在Activity能够匹配隐式Intent。如果不存在匹配的Activity,则resolveActivity返回null。