一文带你吃透HolderFragment 实现ViewModel的生命周期穿透!

238 阅读3分钟

在 Android 开发中,若要将 HolderFragment 的数据持久化能力与 ViewModel 的生命周期感知能力结合,可以通过 ViewModel + HolderFragment 混合模式实现更灵活的数据管理。

一、核心设计思想

  • ViewModel 负责管理界面相关的数据,天然支持配置变更时的数据保留。
  • HolderFragment 作为底层容器,通过 setRetainInstance(true) 实现跨 Activity 生命周期的数据持久化(适用于非配置变更场景)。
  • 结合优势:利用 ViewModel 的官方生命周期管理,同时通过 HolderFragment 实现更底层的数据控制。

二、实现步骤

步骤1:创建自定义 ViewModel

定义 ViewModel 子类,封装需要持久化的数据:

class CustomViewModel : ViewModel() {
    // 普通数据(由 ViewModel 自动保留)
    var counter: Int = 0

    // 需要跨进程重建的复杂数据(通过 HolderFragment 持久化)
    lateinit var persistentData: SomeComplexData
}

步骤 2:实现 HolderFragment 增强层

创建 HolderFragment 作为 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() // 清理资源
    }
}

步骤 3:在 Activity 中绑定 HolderFragment

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 的引用:

class HolderFragment : Fragment() {
    private var retainedViewModel: CustomViewModel? = null

    fun retainViewModel(viewModel: CustomViewModel) {
        retainedViewModel = viewModel
    }

    fun getRetainedViewModel() = retainedViewModel
}

在 Activity 中恢复数据:

override fun onCreate(savedInstanceState: Bundle?) {
    // 恢复 ViewModel
    viewModel = holderFragment.getRetainedViewModel() ?: CustomViewModel().also {
        holderFragment.retainViewModel(it)
    }
}

四、与纯 ViewModel 方案的对比

特性纯 ViewModelViewModel + HolderFragment
配置变更保留
Activity 完全销毁保留✅(通过 HolderFragment)
官方支持❌(需自定义实现)
内存泄漏风险中(需手动管理引用)
适用场景常规页面数据跨页面/跨进程的全局数据

五、高级优化技巧

5.1、自动注入框架

通过 Dagger/Hilt 实现依赖注入:

@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:

class CustomViewModel : ViewModel() {
    private val _data = MutableLiveData<String>()
    val data: LiveData<String> = _data

    fun updateData(newValue: String) {
        _data.value = newValue
    }
}

5.3、进程死亡恢复

结合 SavedStateHandle 实现数据持久化:

class CustomViewModel(private val state: SavedStateHandle) : ViewModel() {
    init {
        state.setSavedStateProvider("data") {
            Bundle().apply { putString("key", persistentData) }
        }
    }
}

六、注意事项

  1. 内存泄漏:避免在 HolderFragment 中持有 Activity 强引用,使用 WeakReference
  2. 线程安全:对 HolderFragment 中的数据访问使用同步锁:
private val lock = Any()
fun safeUpdateData() {
    synchronized(lock) {
        // 修改共享数据
    }
}
  1. 生命周期边界:在 onDetach() 中清理不需要的引用:
override fun onDetach() {
    super.onDetach()
    retainedViewModel = null
}

总结

通过这种混合模式,既可以享受 ViewModel 官方架构组件的便捷性,又能通过 HolderFragment 实现更灵活的数据控制,尤其适合需要 跨 Activity 数据共享 或 长时间数据保留 的复杂场景。

更多分享

  1. Android Jetpack相关面试题分享(一)
  2. Android Jetpack相关面试题分享(二)
  3. Android 架构以及优化相关面试题分享
  4. Android Kotlin协程相关面试题分享
  5. Android 互联网大厂,高频重点面试题集分享(一)