在 Android 开发中,若要将 HolderFragment
的数据持久化能力与 ViewModel
的生命周期感知能力结合,可以通过 ViewModel + HolderFragment 混合模式实现更灵活的数据管理。
一、核心设计思想
- ViewModel 负责管理界面相关的数据,天然支持配置变更时的数据保留。
- HolderFragment 作为底层容器,通过
setRetainInstance(true)
实现跨 Activity 生命周期的数据持久化(适用于非配置变更场景)。 - 结合优势:利用 ViewModel 的官方生命周期管理,同时通过 HolderFragment 实现更底层的数据控制。
二、实现步骤
步骤1:创建自定义 ViewModel
定义 ViewModel
子类,封装需要持久化的数据:
kotlin 代码解读复制代码class CustomViewModel : ViewModel() {
// 普通数据(由 ViewModel 自动保留)
var counter: Int = 0
// 需要跨进程重建的复杂数据(通过 HolderFragment 持久化)
lateinit var persistentData: SomeComplexData
}
步骤 2:实现 HolderFragment 增强层
创建 HolderFragment
作为 ViewModel 的持久化载体:
kotlin 代码解读复制代码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() // 清理资源
}
}
步骤 3:在 Activity 中绑定 HolderFragment
kotlin 代码解读复制代码class MainActivity : AppCompatActivity() {
private lateinit var holderFragment: HolderFragment
private lateinit var viewModel: CustomViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 绑定 HolderFragment
holderFragment = supportFragmentManager.findFragmentByTag("HolderFragment") as? HolderFragment
?: HolderFragment().also {
supportFragmentManager.beginTransaction().add(it, "HolderFragment").commitNow()
}
// 通过自定义 ViewModelStore 获取 ViewModel
val factory = ViewModelProvider.AndroidViewModelFactory(application)
viewModel = ViewModelProvider(holderFragment.getCustomViewModelStore(), factory)
.get(CustomViewModel::class.java)
// 使用 ViewModel 数据
viewModel.counter++
Log.d("MainActivity", "Counter: ${viewModel.counter}")
}
}
三、关键技术点解析
3.1、ViewModel 生命周期控制
- 默认行为:ViewModel 在 Activity 配置变更时自动保留,但 Activity 正常销毁(如用户退出)时会被清除。
- 增强场景:通过
HolderFragment
的retainInstance=true
,让 ViewModel 在 Activity 完全销毁后仍可保留(需谨慎使用,避免内存泄漏)。
3.2、数据持久化范围控制
数据类型 | 存储位置 | 生命周期范围 |
---|---|---|
普通数据(counter) | ViewModel | 配置变更期间保留 |
复杂数据(persistentData) | HolderFragment | 跨 Activity 销毁/重建(非配置变更) |
3.3、双向绑定示例
在 HolderFragment
中保存 ViewModel 的引用:
kotlin 代码解读复制代码class HolderFragment : Fragment() {
private var retainedViewModel: CustomViewModel? = null
fun retainViewModel(viewModel: CustomViewModel) {
retainedViewModel = viewModel
}
fun getRetainedViewModel() = retainedViewModel
}
在 Activity 中恢复数据:
kotlin 代码解读复制代码override fun onCreate(savedInstanceState: Bundle?) {
// 恢复 ViewModel
viewModel = holderFragment.getRetainedViewModel() ?: CustomViewModel().also {
holderFragment.retainViewModel(it)
}
}
四、与纯 ViewModel 方案的对比
特性 | 纯 ViewModel | ViewModel + HolderFragment |
---|---|---|
配置变更保留 | ✅ | ✅ |
Activity 完全销毁保留 | ❌ | ✅(通过 HolderFragment) |
官方支持 | ✅ | ❌(需自定义实现) |
内存泄漏风险 | 低 | 中(需手动管理引用) |
适用场景 | 常规页面数据 | 跨页面/跨进程的全局数据 |
五、高级优化技巧
5.1、自动注入框架
通过 Dagger/Hilt 实现依赖注入:
kotlin 代码解读复制代码@Module
@InstallIn(FragmentComponent::class)
object HolderModule {
@Provides
fun provideViewModel(holderFragment: HolderFragment): CustomViewModel {
return ViewModelProvider(holderFragment.getCustomViewModelStore()).get(CustomViewModel::class.java)
}
}
5.2、支持 LiveData 观察
在 ViewModel 中集成 LiveData:
kotlin 代码解读复制代码class CustomViewModel : ViewModel() {
private val _data = MutableLiveData()
val data: LiveData = _data
fun updateData(newValue: String) {
_data.value = newValue
}
}
5.3、进程死亡恢复
结合 SavedStateHandle
实现数据持久化:
kotlin 代码解读复制代码class CustomViewModel(private val state: SavedStateHandle) : ViewModel() {
init {
state.setSavedStateProvider("data") {
Bundle().apply { putString("key", persistentData) }
}
}
}
六、注意事项
- 内存泄漏:避免在
HolderFragment
中持有 Activity 强引用,使用WeakReference
。 - 线程安全:对
HolderFragment
中的数据访问使用同步锁:
kotlin 代码解读复制代码private val lock = Any()
fun safeUpdateData() {
synchronized(lock) {
// 修改共享数据
}
}
- 生命周期边界:在
onDetach()
中清理不需要的引用:
kotlin 代码解读复制代码override fun onDetach() {
super.onDetach()
retainedViewModel = null
}
总结
通过这种混合模式,既可以享受 ViewModel
官方架构组件的便捷性,又能通过 HolderFragment
实现更灵活的数据控制,尤其适合需要 跨 Activity 数据共享 或 长时间数据保留 的复杂场景。
评论记录:
回复评论: