一、ViewModel 生命周期穿透3种黑科技实现
1.1、HolderFragment寄生在Activity中的“数据保险箱”
一文带你吃透HolderFragment实现ViewModel的生命周期穿透!
原理剖析:
当调用ViewModelProviders.of(activity)时,系统会动态注入一个无UI的HolderFragment。这个Fragment的setRetainInstance(true)属性,使其在Activity重建时仍存活于内存中,其内部通过ViewModelStore对象缓存所有ViewModel实例。
示例代码:
class HolderFragment : Fragment() {
private val viewModelStore = ViewModelStore()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true // 关键:跨配置变更保留
}
// 暴露 ViewModelStore 给宿主 Activity
fun getCustomViewModelStore() = viewModelStore
override fun onDestroy() {
super.onDestroy()
viewModelStore.clear() // 清理资源
}
}
- 此设计让ViewModelStore与Activity生命周期解耦,实现
跨配置变更的数据持久化。
1.2、ViewModelStoreOwner多组件共享的“数据枢纽”
场景痛点:
传统开发中,Activity与Fragment间的数据传递需要通过Bundle或接口回调,而ViewModel通过ViewModelStoreOwner接口,允许不同组件共享同一ViewModel实例。
实现技巧:
- 通过扩展
ViewModelProvider的owner参数,支持Activity/Fragment/Navigation图等不同作用域 - 在
Fragment中调用ViewModelProviders.of(parentFragment),可获取父容器的ViewModel
示例代码:
// 在Fragment中获取Activity级别的ViewModel
val sharedModel: SharedViewModel by viewModels(requireActivity())
- 该设计使得跨组件通信的代码量可减少50%以上。
1.3、SavedStateHandle进程级重建的“最后防线”
突破性能力:
ViewModel默认只能抵御配置变更,但进程被系统杀死时数据仍会丢失。通过集成SavedStateHandle,可将数据写入系统管理的Bundle,实现跨进程销毁的数据恢复。
实现的示例代码:
class StoreViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
val liveData: MutableLiveData<String> = savedStateHandle.getLiveData("key")
init {
savedStateHandle.setSavedStateProvider("key") {
Bundle().apply { putString("key", liveData.value) }
}
}
}
- 底层通过
AbstractSavedStateViewModelFactory,在ViewModel初始化时自动注入SavedStateHandle对象。
二、Jetpack相关组件的高频面试题
2.1、ViewModel与onSaveInstanceState有何本质区别?
- 作用范围:
ViewModel适用于大数据对象(如图片列表),而Bundle适合存储轻量级状态(如页面滚动位置) - 生命周期:
ViewModel存活到组件完全销毁(如Activity调用finish()),而Bundle仅在临时重建时有效 - 性能对比:
ViewModel通过内存缓存避免序列化开销,性能提升约30倍
2.2、如何实现自定义生命周期的ViewModel?
实现方案:
- 1). 继承ViewModel并重写
onCleared() - 2). 通过
ViewModelProvider.Factory注入自定义作用域 - 3). 使用
LifecycleObserver监听特定生命周期事件
示例代码:
public class CustomViewModel extends ViewModel {
@Override
protected void onCleared() {
// 释放资源
}
}
三、ViewModel的三大应用场景
- 跨屏幕旋转:
HolderFragment + ViewModelStore机制 - 跨组件通信:
ViewModelStoreOwner的多级作用域控制 - 跨进程恢复:
SavedStateHandle与Bundle的深度集成