Activity是Android四大组件之一,我们在Android设备上打开一款App的时候,看到的界面就是一个Activity,上面承载了很多UI元素,例如:文本框、按钮、输入框 等。
关于Activity,需要掌握一下基本的开发知识:
-
Activity的生命周期
-
Activity的启动模式
-
Activity间的通信方式
-
Activity的状态保存与恢复
-
Activity与Fragment的关系
1、Activity的生命周期
生命周期方法在 界面状态发生变化 的时候 回调,不是开发者手动调用后触发界面状态变化
当我们打开一款App的时候,系统会创建一个界面和用户进行交互,此时会依次回调onCreate、onStart、onResume方法,其中,
onCreate 仅在Activity创建的时候执行一次,此时Activity处于 不可见 的状态;onStart 被回调时,Activity由 不可见变为可见 状态,但仍 未进入前台 和用户进行交互;onResume 被回调时,Activity已经 进入前台,此时用户可以通过Button等UI元素和App进行交互
-
为什么onStart和onResume不合并成一个函数? 职责分明
注意:
界面 可见状态 和 进入前台 状态的区别:
可见状态:可以看到界面,但不一定能和用户进行交互,例如:全屏的界面A被一个消息弹窗遮挡,界面A处于可见状态,但用户无法与之交互
前台:不仅界面可见,还能和用户进行交互,例如上述案例的弹窗
当用户触发弹窗 局部遮挡 界面时,onPause方法被回调,此时Activity处于 失去焦点,但仍然可见 的状态;
当用户 点击Home键,将App切换到后台 时,onStop方法被回调,此时Activity处于 完全不可见 的状态;此时,如果用户 重新将App切回前台,会依次回调 onStop、onRestart、onStart和onResume方法
-
当用户将Activity切到后台,又切回前台,生命周期如何变化?
当Activity被切到后台时:会依次回调onPause()和onStop()方法
onPause():Activity失去焦点
onStop():Activity完全不可见
当Activity从后台切回前台时:回调顺序为onRestart()、onStart()和onResume()
onRestart(): Activity重新启动
onStart(): Activity变为可见
onResume(): Activity获得焦点,可以与用户交互
-
当屏幕发生旋转的时候,Activity的生命周期函数被回调的次序?
当Activity发生屏幕旋转时,Activity 会 被销毁,再重建,其生命周期方法被回调的次序为:
Activity 被销毁:onPause->onStop->onDestroy
Activity 被重建:onCreate->onStart->onResume
2、Activity的启动模式
指的是一个Activity应该以 何种启动模式 启动,再跳转到另一个Activity。常见的启动模式有四种:standard、singleTop、singleTask和singleInstance。其中,
-
standard 是 默认 的启动模式,每次启动都会 创建新的Activity实例放入任务栈
-
singleTop 是 栈顶复用模式,如果目标Activity 已在栈顶,则 复用 该Activity;否则,创建新的Activity实例放入任务栈
-
singleTask 是 栈内单例模式,这种模式下任务栈中 只有一个 目标Activity实例。如果目标Activity 不在栈顶,则会将其之上的Activity 出栈;如果没有目标Activity,则创建新的Activity实例放入任务栈
-
singleInstance 是 单实例模式,会 单独创建 一个新的任务栈存放目标Activity
启动模式一般通过两种方式指定:
-
通过 AndroidMinifest.xml 文件,通过 lanchMode 属性指定
<activity android:name=".MyActivity"
android:launchMode="singleTop"/>
-
通过 Intent 的 setFlags 方法设定
Intent intent = new Intent(this, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
注意:
任务栈:用来 存放Activity实例 的数据结构,通过 taskId 作为 唯一标识 进行管理
taskAffinity:通过该值 确定Activity属于哪个任务栈
onNewIntent:
当启动模式为 singleTop 的Activity,若处于 栈顶,会 回调onNewIntent,而不是创建新的实例
当启动模式为 singleTask / singleInstance 时,若任务栈中 已存在 该Activity的实例,也会回调onNewIntent方法;需手动调用setIntent方法更新Activity的Intent对象,否则getIntent获取的仍然是旧的Intent对象
与生命周期方法的关系:onNewIntent -> onRestart -> onStart -> onResume
创建Activity的时候,可以通过设定taskAffinity指定从属的任务栈,其 默认值 为 包名
taskAffinity 和 singleTask 启动模式联系紧密,其交互如下:
-
如果查找到 匹配 的taskAffinity:
-
若 已在栈中,那么会将该Activity之上的所有其它Activity出栈,确保其在栈中唯一,并且处于栈顶
-
若 不在栈中,则会新创建一个 新的Activity实例 放到该任务栈中
-
-
如果 没有匹配的taskAffinity,那么会首先创建一个新的任务栈,再将Activity实例放入该任务栈中
<activity android:name=".MainActivity"
android:launchMode="singleTask"
android:taskAffinity="com.example.customtask"/>
3、Activity状态保存和恢复
-
onSaveInstanceState:接收一个 Bundle对象 ,以 Key-Value键值对 的形式 保存 数据;在 onCreate 和 onRestoreInstanceState 方法中通过 Bundle对象 恢复
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("key", "value");
outState.putInt("score", currentScore);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
String value = savedInstanceState.getString("key");
int score = savedInstanceState.getInt("score", 0);
}
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// 这里的 savedInstanceState 总是非 null
String someData = savedInstanceState.getString("key");
}
注意:
onSaveInstanceState 在 onStop之后,onDestroy 之前 调用
onCreate 中的Bundle对象 可能为空,因为 第一次构建Activity 的时候会回调onCreate方法,此时 Bundle对象为空
onRestoreInstanceState中的Bundle对象 不为空 :Activity被销毁前回调onSaveInstanceState方法,将Bundle对象与Activity进行关联;恢复的时候会检查是否有与之关联的保存状态(Bundle对象),如果有则回调onRestoreInstanceState传入该Bundle对象
-
通过 ViewModel 保存&恢复数据
4、Fragment
Fragment可以看作是Activity的一个模块化部分,用于展示各种UI元素;并且,具有自己的生命周期方法,但是需要依附于Activity,受Activity生命周期的影响。
-
生命周期方法
onAttach:Fragment 和 Activity 相关联,是Fragment生命周期的 起点
onCreate:初始化 Fragment,此时还没有UI
onCreateView:创建并返回 Fragment的 层次结构,通过调用 inflate方法 加载布局,返回的是Fragment的 根视图RootView
onViewCreated:在onCreateView之后立即调用,因为前者创建了视图,但没有和父容器进行关联,因此在这里需要通过findViewById等方法,完成视图的初始化操作(通常在这里执行这类操作会 更保险,因为此时 视图已经创建)
onActivityCreated:当依附的Activity的onCreate方法完成时调用,此时可以与Activity的视图交互
onStart:Fragment 可见,但未进入前台和用户交互
onResume:Fragment 进入前台,用户可通过Button等UI元素和用户进行交互
onPause:Fragment 被局部遮挡,失去焦点无法和用户进行交互
onStop:Fragment 进入前台,此时界面不可见
onDestroyView:Fragment的视图 被移除
onDestroy:Fragment 被销毁
onDetach:Fragment与Activity 解除关联
注意:
Fragment的生命周期方法,在Activity对应的生命周期方法中调用,因此其 执行次序在Activity对应的方法之后,例如:Fragment的onResume在Activity的onResume之后执行
与Activity生命周期的关联:
-
当Activity创建时:Activity onCreate() -> Fragment onAttach() -> Fragment onCreate() -> Fragment onCreateView() -> Fragment onActivityCreated()
-
当Activity启动时:Activity onStart() -> Fragment onStart()
-
当Activity恢复时:Activity onResume() -> Fragment onResume()
-
当Activity暂停时:Activity onPause() -> Fragment onPause()
-
当Activity停止时:Activity onStop() -> Fragment onStop()
-
当Activity销毁时:Activity onDestroy() -> Fragment onDestroyView() -> Fragment onDestroy() -> Fragment onDetach()
-
Fragment 与 Fragment / Activity 的通信方法?
一般使用 ViewModel 持有数据,在 Fragment 与 Fragment / Activity 之间进行共享比较稳妥
虽然也有使用 EventBus 发送和接收消息,但是这种方式存在: 1、在业务复杂的场景下,容易被滥用,进而导致消息溯源困难;2、以Object对象传递数据,这样使用的时候需要强转数据类型,缺了编译器的类型检查,存在运行时崩溃等风险;3、需要手动注册和释放,存在内存泄漏风险等

被折叠的 条评论
为什么被折叠?



