| 概念 | 主要职责 |
|---|---|
| Lifecycle | 管理组件的生命周期状态,比如 Activity/Fragment 当前是创建、启动、暂停、销毁 |
| ViewModel | 保存和管理界面相关数据,让数据在配置变化时不丢失,比如屏幕旋转 |
简单说:
Lifecycle 管“界面活没活着”
ViewModel 管“界面需要的数据”
1. Lifecycle 是什么?
Lifecycle 是 Android Jetpack 提供的生命周期管理组件。
它用来感知:
- Activity 是否创建了
- Fragment 是否可见
- 页面是否进入后台
- 页面是否销毁
常见生命周期状态:
INITIALIZED
CREATED
STARTED
RESUMED
DESTROYED
常见生命周期事件:
ON_CREATE
ON_START
ON_RESUME
ON_PAUSE
ON_STOP
ON_DESTROY
Activity 常见生命周期方法
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 初始化界面、ViewModel、监听器
}
override fun onStart() {
super.onStart()
// 页面开始可见
}
override fun onResume() {
super.onResume()
// 页面可以交互
}
override fun onPause() {
super.onPause()
// 页面失去焦点,例如弹窗、跳转
}
override fun onStop() {
super.onStop()
// 页面不可见
}
override fun onDestroy() {
super.onDestroy()
// 页面销毁,释放资源
}
}
Fragment 常见生命周期方法
class HomeFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 初始化非 View 相关数据
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// 创建 Fragment 的 View
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// View 创建完成,初始化控件、观察数据
}
override fun onDestroyView() {
super.onDestroyView()
// View 被销毁,清理 binding 等
}
override fun onDestroy() {
super.onDestroy()
// Fragment 被销毁
}
}
2. Lifecycle 常用方式
方式一:lifecycleScope
在 Activity/Fragment 中启动协程,并自动跟随生命周期取消。
lifecycleScope.launch {
// 执行协程任务
}
例如:
lifecycleScope.launch {
delay(1000)
textView.text = "加载完成"
}
当 Activity/Fragment 销毁时,这个协程会自动取消。
方式二:repeatOnLifecycle
这是现在非常常用的方式,尤其配合 Flow。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
// 更新 UI
}
}
}
含义是:
当页面至少处于 STARTED 状态时收集数据;
页面 STOP 后自动停止收集;
页面重新 START 后重新收集。
这比直接 collect 更安全。
方式三:LifecycleObserver
可以写一个类来观察生命周期。
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
println("页面开始可见")
}
override fun onStop(owner: LifecycleOwner) {
println("页面不可见")
}
}
使用:
lifecycle.addObserver(MyObserver())
适合封装某些需要感知生命周期的组件,比如定位、播放器、传感器等。
3. ViewModel 是什么?
ViewModel 用来保存和管理 UI 数据。
它的特点是:
- 不直接持有 View
- 不应该持有 Activity、Fragment 的引用
- 屏幕旋转时不会被重新创建
- Activity/Fragment 销毁时才会真正清除
例如:页面上展示用户信息、列表数据、加载状态,这些就适合放在 ViewModel 里。
ViewModel 示例
class MainViewModel : ViewModel() {
private val _name = MutableStateFlow("张三")
val name: StateFlow<String> = _name
fun changeName(newName: String) {
_name.value = newName
}
override fun onCleared() {
super.onCleared()
// ViewModel 被清除时调用
}
}
在 Activity 中使用:
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.name.collect { name ->
textView.text = name
}
}
}
}
}
4. ViewModel 常用方法和写法
1)viewModelScope
viewModelScope 是 ViewModel 中最常用的协程作用域。
class UserViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch {
// 请求网络、查询数据库
}
}
}
当 ViewModel 被销毁时,viewModelScope 中的任务会自动取消。
2)onCleared()
ViewModel 被真正销毁时调用。
override fun onCleared() {
super.onCleared()
// 释放资源
}
例如关闭某些流、取消特殊任务等。
不过一般使用 viewModelScope 的话,不需要手动取消协程。
3)LiveData
以前常用,现在很多项目仍然在用。
class MainViewModel : ViewModel() {
private val _name = MutableLiveData<String>()
val name: LiveData<String> = _name
fun changeName() {
_name.value = "李四"
}
}
Activity 观察:
viewModel.name.observe(this) { name ->
textView.text = name
}
Fragment 里建议用:
viewModel.name.observe(viewLifecycleOwner) { name ->
textView.text = name
}
4)StateFlow
现在更推荐的方式。
class MainViewModel : ViewModel() {
private val _uiState = MutableStateFlow(MainUiState())
val uiState: StateFlow<MainUiState> = _uiState
fun updateTitle(title: String) {
_uiState.value = _uiState.value.copy(title = title)
}
}
data class MainUiState(
val title: String = "",
val loading: Boolean = false
)
Activity/Fragment 收集:
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
textView.text = state.title
progressBar.isVisible = state.loading
}
}
}
5. Lifecycle 和 ViewModel 的配合关系
一个常见结构是:
Activity / Fragment
↓ 观察数据
ViewModel
↓ 调用
Repository
↓ 获取数据
网络 / 数据库
职责划分:
Activity / Fragment
负责:
- 初始化 View
- 监听点击事件
- 观察 ViewModel 数据
- 根据数据更新 UI
不建议做:
- 大量业务逻辑
- 网络请求细节
- 数据处理逻辑
ViewModel
负责:
- 保存 UI 状态
- 处理页面逻辑
- 调用 Repository 获取数据
- 暴露 LiveData / StateFlow 给界面
不建议做:
- 持有 Activity/Fragment/View
- 直接操作控件
- 弹 Toast、跳页面这种强 UI 行为,除非用事件形式通知页面
Lifecycle
负责:
- 感知当前页面状态
- 控制协程、数据观察、资源释放
- 避免内存泄漏和无效 UI 更新
6. 一个完整例子
ViewModel
class UserViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UserUiState())
val uiState: StateFlow<UserUiState> = _uiState
fun loadUser() {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(loading = true)
try {
delay(1000)
_uiState.value = UserUiState(
loading = false,
name = "张三"
)
} catch (e: Exception) {
_uiState.value = UserUiState(
loading = false,
error = "加载失败"
)
}
}
}
}
data class UserUiState(
val loading: Boolean = false,
val name: String = "",
val error: String? = null
)
Activity
class UserActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
progressBar.isVisible = state.loading
nameTextView.text = state.name
state.error?.let {
Toast.makeText(this@UserActivity, it, Toast.LENGTH_SHORT).show()
}
}
}
}
viewModel.loadUser()
}
}
这里:
Activity负责显示 UIViewModel负责加载和保存数据Lifecycle负责在合适生命周期收集数据
7. 最容易混淆的点
问题 1:ViewModel 会不会随着 Activity 的 onDestroy 一起销毁?
不一定。
比如屏幕旋转时:
旧 Activity onDestroy
新 Activity onCreate
ViewModel 不销毁
ViewModel 会被保留。
但如果用户真正退出页面,比如按返回键:
Activity finish
ViewModel onCleared
ViewModel 才销毁。
问题 2:为什么 ViewModel 不能持有 Activity?
因为 ViewModel 生命周期可能比 Activity 长。
如果 ViewModel 持有 Activity,屏幕旋转后旧 Activity 无法释放,容易造成内存泄漏。
错误示例:
class MainViewModel(val activity: Activity) : ViewModel()
不推荐。
问题 3:Fragment 中 observe 为什么用 viewLifecycleOwner?
Fragment 的生命周期和它的 View 生命周期不是完全一样的。
Fragment 可能还在,但它的 View 已经销毁了。
所以 Fragment 观察 LiveData 时推荐:
viewModel.data.observe(viewLifecycleOwner) {
// 更新 UI
}
而不是:
viewModel.data.observe(this) {
// 不推荐
}
8. 简单记忆法
你可以这样记:
Lifecycle:页面什么时候活着
ViewModel:页面活着时要显示什么数据
或者:
Lifecycle 管生命周期
ViewModel 管状态和数据
Activity/Fragment 管 UI 展示
常用组合:
private val viewModel: MainViewModel by viewModels()
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
// 更新 UI
}
}
}
这就是现在 Android 里非常常见、比较推荐的写法。