[TOC]
# Activity生命周期
![](https://user-gold-cdn.xitu.io/2020/6/16/172bb94e227f8791?w=513&h=663&f=png&s=45666)
- 1. Launcher 启动 Activity
![](https://user-gold-cdn.xitu.io/2020/6/9/172979a080948e6d?w=504&h=681&f=png&s=32810)
- 2. Activity A 启动 B
![](https://user-gold-cdn.xitu.io/2020/6/10/1729dee8bfb67f4d?w=583&h=541&f=png&s=33560)
如果Activity_B是透明的,则Activity_A不会执行onStop方法,Activity_B返回时,Activity_A直接调用onResume,回到前台。
如果Activity_B不是是透明的,Activity_A设置了属性:android:noHistory="true",则Activity_A不会执行onStop方法,Activity_B返回时,Activity_A直接调用onStop->onDestroy。
设置Activity为透明
```
<style name="TransparentTheme" parent="Theme.AppCompat.NoActionBar">
<!--不设置activity进入和退出动画样式-->
<item name="android:windowAnimationStyle">@null</item>
<!--设置窗口的背景为透明,设置透明背景必须要设置此项-->
<item name="android:windowBackground">@android:color/transparent</item>
<!--设置窗口的背景是否为半透明,设置透明背景必须要设置此项-->
<item name="android:windowIsTranslucent">true</item>
<!--设置状态栏的背景为半透明-->
<item name="android:windowTranslucentStatus">true</item>
</style>
```
# 启动模式与属性
- 1. Activity栈简介
一个ActivityRecord对应一个Activity,一个Activity可能对应多个ActivityRecord,这与Activity的启动模式有关。
![](https://user-gold-cdn.xitu.io/2020/6/15/172b66984c61dc9b?w=172&h=278&f=png&s=9825)
使用adb shell dumpsys activity activities查看Activity栈信息
```
Stack #42: type=standard mode=fullscreen
* TaskRecord{ee49cfc #50 A=com.android.activitydemonstration U=0 StackId=42 sz=2}
affinity=com.android.activitydemonstration
intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.activitydemonstration/.ActivityA}
Activities=[ActivityRecord{2e0e9ef u0 com.android.activitydemonstration/.ActivityA t50}, ActivityRecord{305057 u0 com.android.activitydemonstration/.ActivityB t50}]
stackId=42
* Hist #1: ActivityRecord{305057 u0 com.android.activitydemonstration/.ActivityB t50}
Intent { cmp=com.android.activitydemonstration/.ActivityB }
taskAffinity=com.android.activitydemonstration
state=RESUMED stopped=false delayedResume=false finishing=false
* Hist #0: ActivityRecord{2e0e9ef u0 com.android.activitydemonstration/.ActivityA t50}
packageName=com.android.activitydemonstration processName=com.android.activitydemonstration
launchedFromUid=10068 launchedFromPackage=com.huawei.android.launcher userId=0
app=ProcessRecord{2c0a3f5 1590:com.android.activitydemonstration/u0a155}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.activitydemonstration/.ActivityA bnds=[798,1694][1050,2008] }
taskAffinity=com.android.activitydemonstration
TaskRecord{ee49cfc #50 A=com.android.activitydemonstration U=0 StackId=42 sz=2}
Run #1: ActivityRecord{305057 u0 com.android.activitydemonstration/.ActivityB t50}
Run #0: ActivityRecord{2e0e9ef u0 com.android.activitydemonstration/.ActivityA t50}
mResumedActivity: ActivityRecord{305057 u0 com.android.activitydemonstration/.ActivityB t50}
mLastPausedActivity: ActivityRecord{2e0e9ef u0 com.android.activitydemonstration/.ActivityA t50}
```
- 2. Activity属性
|属性|取值|说明|
|:-|:-|:-|
|taskAffinity|包名格式的字符串(如:.xxx)|activity的亲属关系, 默认为APP的包名|
|launchMode|standard|默认启动模式;A启动B,每次启动都会在A的Task中新建一个B。|
||singleTop|A启动B,B的启动模式为singleTop,启动流程如下所示。![](https://user-gold-cdn.xitu.io/2020/6/16/172bb97452cb2356?w=485&h=505&f=png&s=31886)复用B时,B在onResume前执行noNewIntent。|
||singleTask|Activity A启动Activity B ,B的启动模式为singleTask,如果B的taskAffinity与A的不同,则寻找与B的taskAffinity相同的Task启动B;如果相同则在A的Task中启动B。流程图如下所示。![](https://user-gold-cdn.xitu.io/2020/6/16/172bb9914f8167c1?w=490&h=441&f=png&s=32238)如果B设置了新的taskAffinity,则这个栈会加到最近启动列表中。|
||singleInstance|A启动Activity B ,B的启动模式为singleInstance,新建一个与B的taskAffinity相同的Task启动B,而且这个Task中有且只有B这一个Activity。重复启动B则复用B,复用B时,B在onResume前执行noNewIntent。|
| clearTaskOnLaunch | true/false|A启动B, 然后返回Home, 从新启动 B,如果A设置了这个属性为true,则不显示B,否则显示B |
|configChanges|mcc|国际移动用户识别码所属国家代号是改变了,sim被侦测到了,去更新mcc MCC是移动用户所属国家代号|
||mnc|国际移动用户识别码的移动网号码是改变了, sim被侦测到了,去更新mnc MNC是移动网号码,最多由两位数字组成,用于识别移动用户所归属的移动通信网|
||locale|用户所在区域发生变化,一般是用户切换了语言时,切换后的语言会显示出来|
||touchscreen|触摸屏改变了(通常是不会发生的)|
||keyboard|键盘发生了改变(例如用户用了外部的键盘)|
||keyboardHidden|键盘的可用性发生了改变|
||navigation|导航发生了变化(通常不会发生)|
||orientation|屏幕方向改变了(横竖屏切换)|
||fontScale|字体比例发生了变化(选择了不同的全局字体)|
||screenSize|屏幕大小改变了|
||screenLayout|屏幕的显示发生了变化(不同的显示被激活)|
|||注:Android 4.0之前,设置"orientation keyboardHidden"起作用,Android 4.0之后,除了设置"orientation",还必须设置"keyboardHidden orientation screenSize"|
|enabled|true/false|activity 是否可以被实例化|
|excludeFromRecents|true/false|是否可被显示在最近打开的activity列表里(true不显示,false显示,只有栈的根Activity设置该属性才生效)。|
|exported|true/false|是否允许activity被其它程序调用|
|permission|权限名称|设置启动这个Activity所需要的权限。|
|process|进程名称|一个activity运行时所在的进程名。|
|screenOrientation|unspecified|默认值,由系统决定,不同手机可能不一致|
||landscape|强制横屏显示|
||portrait|强制竖屏显|
||behind|与前一个activity方向相同|
||sensor|根据物理传感器方向转动,用户90度、180度、270度旋转手机方向,activity都更着变化|
||sensorLandscape|横屏旋转,一般横屏游戏会这样设置|
||sensorPortrait|竖屏旋转|
||nosensor|旋转设备时候,界面不会跟着旋转。初始化界面方向由系统控制|
||user|用户当前设置的方向|
|theme|"resource or theme "|activity的样式主题, 如果没有设置,则activity的主题样式从属于应用程序, 参见<application>元素的theme属性|
- 3. Intent的FLAG
Intent中定义了很多个FLAG,其中有几个FLAG也可以设定Activity的启动方式,如果Launch Mode设定和FLAG设定的Activity的启动方式有冲突,则以FLAG设定的为准。
|FLAG|说明|
|:-|:-|
|FLAG_ACTIVITY_SINGLE_TOP|和Launch Mode中的singleTop效果是一样的。|
|FLAG_ACTIVITY_NEW_TASK|寻找和Activity关联(taskAffinity相同)的task,启动Activity;如果没有则新建task,启动Activity|
|FLAG_ACTIVITY_CLEAR_TOP|LaunchMode中没有与此对应的模式,如果要启动的Activity已经存在于栈中,则将所有位于它上面的Activity(包括它自己)出栈,然后启动新的Activity。与FLAG_ACTIVITY_NEW_TASK合用,可打到类似singleTask的效果,但是不会复用Activity。|
|FLAG_ACTIVITY_NO_HISTORY|Activity一旦退出,就不会存在于栈中。同样的,也可以在AndroidManifest.xml中设置“android:noHistory”。|
|FLAG_ACTIVITY_MULTIPLE_TASK|需要和FLAG_ACTIVITY_NEW_TASK一同使用才有效果,系统会启动一个新的栈来容纳新启动的Activity。等同于singleInstance。|
|FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS|Activity不会被放入到“最近启动的Activity”列表中。只有栈的根Activity设置这个FLAG才生效。|
|FLAG_ACTIVITY_CLEAR_TASK|需要和FLAG_ACTIVITY_NEW_TASK一同使用才有效果,用于清除与启动的Activity相关栈的所有Activity。|
# Activity启动方式
- 1. 显示启动
```java
从Activity启动
Intent intent = new Intent(this, ActivityB.class);
startActivity(intent);
从Context启动
Intent intent = new Intent(this, ActivityC.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
```
- 2. 隐式启动
```
<activity
android:name=".ActivityC">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="app"/>
<data android:host="detail_view"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
从Activity启动
Intent intent = new Intent();
intent.setData(Uri.parse("app://detail_view"));
startActivity(intent);
从Context启动
Intent intent = new Intent();
intent.setData(Uri.parse("app://detail_view"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
```
```
<activity
android:name=".ActivityB">
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="com.activity.B"/>
</intent-filter>
</activity>
从Activity启动
Intent intent = new Intent();
intent.setAction("com.activity.B");
startActivity(intent);
从Context启动
Intent intent = new Intent();
intent.setAction("com.activity.B");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
```
网友评论