生命周期
- onCreate();
- onStart(); 可见,
- onResume(); 可操作,在前台
- onPause();
- onStop();
- onDestroy();
- onRestart(); 返回前activity, 让他重新启动
- 当Activity只执行onPause方法时(透明Activity),这时候如果App设置的targetVersion大于11则不会执行onSaveInstanceState方法
处理广播, 在onStart和onStop, onResume和onPause易触发并且可能只是暂时不能执行(被透明activity挡住)
跳转B前操作数据库, 并且B需要数据库, 在onPause,
onPause
onCreate--B
onStart--B
onResume--B
onStop
所以得确保B没出来的时候数据加载完毕, 但是如果B是半透明的, 则不会执行onStop
B返回A
onPause -B
onRestart
onStart
onResume
onStop --B
onDestroy --B
黑屏/按home/按任务列表生命周期:
onPause
onStop
onRestart
onStart
onResume
横竖屏切换生命周期,此时开 alertDialog.Builder 格式的dialog, 生命周期不影响
onPause
onStop
onDestroy
onCreate
onStart
onResume
Activity 是否运行
(activity == null || activity.isDestroyed() || activity.isFinishing())
原因: isFinishing 根据 mFinished, mFinished只在finish
时改变, 无法确定finish一定会执行, 且 finish 执行后, 无法保证立马走到 onDestroy
public boolean isFinishing() {
return mFinished;
}
根据Google源码中的Dialer应用的源码Link, 添加 isDestroyed 判断
@Override
protected void onPostExecute(Void result) {
final Activity activity = progressDialog.getOwnerActivity();
if (activity == null || activity.isDestroyed() || activity.isFinishing()) {
return;
}
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
onUserLeaveHint 和 onUserInteraction
- onUserLeaveHint
当用户的操作导致activity即将进入后台的时候, 此方法会被调用, 但在来电时不被调用 - onUserInteraction
activity 在分发各种事件之前会调用, 但启动另一个activity会被调用两次, 一次是 activity 补货到事件时, 一次是调用activity.onUserLeaveHint之前会调用onUserInteraction
临时状态保存 -- onSaveInstanceState 和 onRestoreInstanceState
是用来临时存储数据, 长期的还是需要数据库
前提是view必须有ID
保存状态
-
onSaveInstanceState(Bundle savedInstanceState)
执行在 onStop 之前- 只有back不会触发
=================== - home触发
- 任务列表键会触发
- 跳转 Activity 会触发
- 旋转屏幕会触发
- 黑屏会触发
Activity 创建时有一个 bundle 对象, 该对象是上次被系统销毁时在 onSaveInstanceState 保存的参数,
```java
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";@Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save the user's current game state savedInstanceState.putInt(STATE_SCORE, mCurrentScore); savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel); // Always call the superclass so it can save the view hierarchy state super.onSaveInstanceState(savedInstanceState); } ``` **注意,自定义的部分在super之前**
使用onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState), 则onSaveInstanceState不会被调用
- 只有back不会触发
-
onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState)
API21 后添加的属性, 能在关机重启后拥有数据恢复的功能, 需要在 manifest 中给 acticity 添加属性android:persistableMode="persistAcrossReboots"
须
- 重写 onCreate(Bundle savedInstanceState, PersistableBundle persistentState),
- 并不用普通的 onCreate 和 onSaveInstanceState
重写此onSaveInstanceState会导致 onSaveInstanceState 不执行
恢复状态
-
onRestoreInstanceState
执行在 onStart 之后, 只有有savedInstanceState时才会调用, 无需判空public void onRestoreInstanceState(Bundle savedInstanceState) { // Always call the superclass so it can restore the view hierarchy super.onRestoreInstanceState(savedInstanceState); // Restore state members from saved instance mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); }
-
onCreate中恢复, 需判空
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Always call the superclass first // Check whether we're recreating a previously destroyed instance if (savedInstanceState != null) { // Restore value of members from saved state mCurrentScore = savedInstanceState.getInt(STATE_SCORE); mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL); } else { // Probably initialize members with default values for a new instance } ... }
透明activity(继承AppCompatActivity)
- 透明color
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<color name="transparent">#0000</color>
</resources>
- style设置background, style的parent不加会报错:
You need to use a Theme.AppCompat theme (or descendant) with this activity.
<style name="myTransParent" parent="Theme.AppCompat.Light.NoActionBar">
<item name ="android:windowBackground">@color/transParent</item>
<item name ="android:windowNoTitle">true</item>
<item name ="android:windowIsTranslucent">true</item>
<item name ="android:colorBackgroundCacheHint">@null</item>
<item name ="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
<item name ="android:statusBarColor">@color/transParent</item>
</style>
- 清单设置 activity 的 theme
android:theme="@style/myTransparent"
ActivityA 打开透明ActivityB
onPause
onCreate --B
onStart --B
onResume --B
透明ActivityB返回ActivityA
onPause --B
onResume
onStop --B
onDestroy --B
启动模式
A组件运行在A应用, A组件调用系统的照相组件, 虽然不在一个应用, 但是安卓运行跨应用组件, 虽然两者不在一个进程, 但是可以通过Task来实现, Task可以理解为实现一个功能而负责管理所有用到的 Activity实例的栈
standard
默认, 先进后出
singleTop
栈顶不重复, 唯一
如果要开启的 activity 已经在栈顶存在, 就不会创建新的实例, 而去调用 onNewIntent().
如果栈顶没有, 则创建新的实例
比如 通知栏的通知点击打开activity, 用singleTop可以避免重复创建
快速点击不能只依赖这个, 不靠谱, 第一个栈实例可能还没入栈,就创建了第二个然后和第一个一起入栈了, 建议对快速点击另作判断
singleTask
栈内不重复, 干掉头上的其他activity
如果要开启的activity已经在栈内存在, 就不会创建新的栈和新的实例, 而去调用 onNewIntent(), 并且清空它上面的所有activity
比如 主界面, 保证主界面上面没有activity
singleInstance
单一实例, 单一栈, 栈里只有自己
谨慎使用
如果要开启的activity已经在进程中存在, 就不会创建新的实例, 而去调用 onNewIntent().
比如 呼叫来电界面
指定启动模式
- manifest指定
<activity android:name=".SecondActivity"
android:launchMode="singleTask"/>
- 代码指定
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
//通过 intent.addFlags 设置
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
-
对比
- 代码指定优先于 manifest
- manifest无法设定singleInstance模式
-
Intent.FLAG_:
- FLAG_ACTIVITY_NEW_TASK = 开新栈, 多用在service和Application, 因为他俩没有栈
- FLAG_ACTIVITY_SINGLE_TOP = singleTop
- FLAG_ACTIVITY_CLEAR_TOP = singleTask
- FLAG_ACTIVITY_NO_HISTORY 启动完其他的后, 自己消失
-
StartActivityForResult 5.0 分水岭
- 5.0 之前可能不回调
- 5.0 后全部有回调
-
adb 查看任务栈
-
运行
adb shell dumpsys activity
-
搜 Recent tasks 查看已经存在的任务栈
Recent tasks: * Recent #0: TaskRecord{5bd8fdd #749 A=com.taskaffinity U=0 sz=1} * Recent #1: TaskRecord{a972e43 #748 A=com.activityfull U=0 sz=1} * Recent #2: TaskRecord{7a2180c #664 I=com.android.launcher3/.Launcher U=0 sz=1}
-
搜 Running activities (most recent first)查看activity
Running activities (most recent first): TaskRecord{25d22cd #684 A=com.activityfull U=0 sz=2} Run #1: ActivityRecord{8e55d0b u0 com.activityfull/.SecondActivity t684} Run #0: ActivityRecord{d26b857 u0 com.activityfull/.MainActivity t684}
栈的唯一标号是#682, sz 表示栈内有几个组件, 栈顶的是 SecondActivity,
- Recent tasks查看手机程序的任务栈, != 应用数(一个应用可能包含多个栈), 更不是进程数
任务栈数 = 手机任务列表里显示的数量 + com.android.launcher + com.android.systemuiACTIVITY MANAGER RECENT TASKS (dumpsys activity recents) Recent tasks: * Recent #0: TaskRecord{42a273f #682 A=com.activityfull U=0 sz=1} * Recent #1: TaskRecord{7a2180c #664 I=com.android.launcher3/.Launcher U=0 sz=1} * Recent #2: TaskRecord{8a01555 #667 A=com.android.systemui U=0 sz=1}
-
android:exported="true"
允许其他app打开这个activity
taskAffinity + allowTaskReparenting
- taskAffinity
设置activity进入指定完整栈名的栈,一般和singleTask一起使用- Application中设置(推荐activity设置), 不设定则默认包名, 设定了内部activity和Application一致
- Activity中设置, 如果指定的任务栈不存在, 那么会自己新开一个指定包名的任务栈
- allowTaskReparenting
是否依附与开启这个activity的任务栈 - 举例:
APP1内有activity1, activity2; APP2内有activity3和activity4, 当APP1 的 activity1 在 APP1 内打开这个 APP2 的 activity4 时,
-
<activity android:name=".FourActivity" android:exported="true" />
a. 只有 APP1 的任务栈打开, 存放的是 activity1 和 activity4;
b. 按home, 点开 APP1 看到的是 activity4, 按back, 看到activity1, 按back, 退出
c. 按home, 点开 APP2 看到的是 activity3, 按back, 退出 -
<activity android:name=".FourActivity" android:exported="true" android:allowTaskReparenting="true" />
a. 只有 APP1 的任务栈打开, 存放的是 activity1 和 activity4;
b. 按home, 点开 APP1 看到的是 activity1,
c. 按home, 点开 APP2 看到的是 activity4, 按back, 看到activity3, 按back, 退出 -
<activity android:name=".FourActivity" android:exported="true" android:allowTaskReparenting="true" android:launchMode="singleTask" />
a. APP1 任务栈存放 activity1, APP2 的任务栈存放activity4
b. 按home, 点开APP1 看到的是 activity1
c. 按home, 点开APP2 看到的是 activity4, 按back退出
参考