题外插入: 之前我一直认为 Android studio 无线调试手机是需要在 Android studio 安装插件的, 比如 ADB wifi等, 今天我知道只需要电脑和手机在 同一个局域网内 然后通过adb命令即可链接,手机也不需要root, 比如我的手机ip是 192.168.3.165, 只需
adb connect 192.168.3.165
就会提示 connected to 192.168.3.165:5555, 然后 adb devices 就会看到:
List of devices attached
192.168.3.165:5555 device
Activity 生命周期方法
1 onCreate
第一个生命周期方法, 标识 Activity 正在被创建,做一些数据初始化操作, 比如 setContentView 去加载布局, 当前页面有需要网络请求初始化操作也可以放在这里进行
2 onStart
表示当前 Activity 正在启动, 但是还没有出现在前台, 不能和用户进行交互, 我们还看不到 Activity
3 onResume
Activity 已经可见, 出现在前台并且可以和用户进行交互, 和 onStart 明显的区别是 onStart 的时候 Activity 还不能和用户进行交互
4 onPause
Activity 正在停止,紧接着就会调用 onStop, 如果这个时候突然重新打开 Activity, 那么 onResume 方法将会被调用,此时可以进行一些基本的数据保存, 不能做耗时操作, 因为下一个 Activity 即将显示
5 onStop
Activity 即将停止, 可以做一些比 onPause 稍微耗时一点的操作, 比如关闭定时器
6 onDestroy
Activity 即将被销毁,是生命周期的最后一个回调, 这里可以做资源释放操作, 解绑广播等等
借用官网流程图, 官网地址
容易混淆的情况说明
1 Activity 第一次启动会调用: onCreate-onStart-onResume
2 当切换到桌面的时候 onPause-onStop, 如果 Activity 采用了透明主题, 那么不会回调 onStop
3 用户再次打开应用 onRestart-onStart-onResume
4 生命周期方法都是一一对应的,
onCreate 和 onDestroy 相对应, 分别标识着创建和销毁, 并且只能调用一次, 再次启动相同 Activity 将会启动一个新的 Activity 这里指启动模式为标准模式的情况下, 随着屏幕的点亮和熄灭, onResume 和 onPause , onStart 和 onStop 都会执行多次
那么 onStart 和 onResume 到底有什么区别?
onStart 是从 Activity 是否可见来回调的, onResume 是从 Activity 是否在前台来回调
异常情况下导致 Activity 重新创建怎么处理, 如果用户突然旋转屏幕, 那么在默认情况 Activity 会销毁并且重新创建, 当然我们可以通过更改配置来阻止这种情况的发生, 如果 Activity 异常终止, 那么系统会调用 onSaveInstanceState 来保存状态, 会在 onStop 之前调用, 和 onPause 没有时间上的区分, 当Activity 重新创建后, 调用 onRestoreInstanceState 来恢复状态, 在 Activity 销毁前 onSaveInstanceState 会将 Bundle 对象作为参数传递给 onRestoreInstanceState 和 onCreate 方法, 此时我们就可以判断 Activity 是否被重建了, 如果重建了我们就可以取出之前保存的数据进行恢复, onRestoreInstanceState 方法会在 onStart 之前被调用, 一般情况系统会做一些数据的恢复工作, 比如输入的文本框, ListView的滑动位置等等
当用户突然旋转屏幕时, 如果当前 Activity 配置android:configChanges=”orientation|keyboardHidden” , 然后在 Activity 中重写下面的方法, 此时旋转屏幕不会重启 Activity
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
Activity 启动模式
上面描述了 Activity 的生命周期, 接下来记录一下启动模式的学习。
Android 系统里面多个 Activity 是使用任务栈来管理, 栈是一种 “后进先出“ 的结构, 每点击一次 back 按键就会有一个 Activity 出栈, 但是多次启动同一个 Activity 就会重复创建多个实例, Android 系统肯定是不允许这样情况发生的, 所以提供了启动模式。
standard 标准模式
系统默认模式, 每次启动 Activity 都会创建一个新的实例, 不管这个实例是否存在, 在这种模式下, 当前 Activity 是由哪个 Activity 启动的就和它在相同的栈中, 用 Application 的 Context 启动 Activity 就会报错, 因为当前 Context 并不属于任何任务栈, 这种情况可以加标志位 FLAG_ACTIVITY_NEW_TASK 启动一个新的任务栈
singleTop 栈顶复用模式
在这个模式下, 如果新的 Activity 已经位于任务栈的栈顶, 那么此 Activity 不会被创建, 同时会执行它的 onNewIntent 方法, 这个方法返回一个 intent 用来存储请求的信息, 此时需要注意 onCreate, onStart 等方法将不会被调用, 因为它没有发生任何改变, 当然如果新的 Activity 没有位于栈顶, 那么它还是会被重新创建, 比如栈情况是 ABCD, A 位于栈底部, D 位于顶部, 此时启动 D,如果 D 的启动模式是 singleTop, 那么栈里的情况还是 ABCD, 如果将 D 的模式改为 standard , 那么栈内情况会变成 ABCDD。
singleTask 栈内复用模式
一种单例模式, 这种模式的 Activity 启动的时候都不会重新创建实例, 也会调用 onNewIntent 方法, 并且处于这种模式的 Activity 有清空在它上面 Activity 的左右, 比如栈内有 ABCD 四个 Activity, C 是singleTask 模式的, 这个时候启动 C, 不会重新创建 C 的实例, 而是回调它的 onNewIntent方法, 并且清空它上面的 Activity , 此时栈内应该是 ABC。
singleInstance 单实例模式
是一种加强的 singleTask 模式, 出了具有 singleTask 的所有特性之外, 具有这种启动模式的 Activity 将单独位于一个任务栈中,比如你的应用里面要推广一个应用列表, 就可以把应用列表页面作为这种模式。
TaskAffinity 任务相关性
TaskAffinity 标识了 Activity 所需要的任务栈名字, 默认所有 Activity 任务栈名字应该为应用的包名, TaskAffinity 和 SingleTask 或者 allowTaskReparenting 配对使用, 在其他情况下没有任何意义。
当 TaskAffinity 和 SingleTask 一同使用的时候, 它是具有该模式的 Activity 目前任务栈的名字, 待启动的 Activity 会运行在名字和 TaskAffinity 相同的任务栈中。
当 TaskAffinity 和 allowTaskReparenting 一起使用的时候 , 会产生特殊的效果, 当一个应用 A 启动了应用 B 的某个 Activity 之后,当这个 Activity 的 allowTaskReparenting 为true的话, 那么当应用 B 启动后, 这个 Activity 会直接从 A 的任务栈转移到 B 的任务栈, 如果此时按 Home 按键回到了桌面, 然后再次启动 B 的时候此时看到不是 B 的主页面而是这个 Activity 页面 , 但是这个时候 B 已经有了自己的任务栈, 此时系统发现原本属于 B 应用的 C 就把 C 从 A 的任务栈转移回了 B 的任务栈, 那么这个时候点击返回键呢? 答案当然是 B 的主页面, 很绕, 所以我这里我写了一个 Demo 放在了 github
感谢 Android开发艺术探索 一书