Activity生命周期
- Launcher 启动 Activity
- Activity A 启动 B
如果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>
启动模式与属性
- Activity栈简介
一个ActivityRecord对应一个Activity,一个Activity可能对应多个ActivityRecord,这与Activity的启动模式有关。
使用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}
- Activity属性
属性 | 取值 | 说明 |
---|---|---|
taskAffinity | 包名格式的字符串(如:.xxx) | activity的亲属关系, 默认为APP的包名 |
launchMode | standard | 默认启动模式;A启动B,每次启动都会在A的Task中新建一个B。 |
singleTop | A启动B,B的启动模式为singleTop,启动流程如下所示。复用B时,B在onResume前执行noNewIntent。 | |
singleTask | Activity A启动Activity B ,B的启动模式为singleTask,如果B的taskAffinity与A的不同,则寻找与B的taskAffinity相同的Task启动B;如果相同则在A的Task中启动B。流程图如下所示。如果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的主题样式从属于应用程序, 参见元素的theme属性 |
- 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启动方式
- 显示启动
从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);
- 隐式启动
<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);