5

Is it possible to provide once own implementation of a ViewModelStore for ViewModelProviders to use instead of the default one?

More precisely, I'm interested in adding fun clear(vm: ViewModel) (or using an index or something similar) functionality to the ViewModelStore so that I can clear a single view model of my choice, not just use the built in ViewModelStore#clear:

public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.onCleared();
    }
    mMap.clear();
}

which clears all view models.

4

1 回答 1

6

首先,我认为您不应该考虑这样做,因为这是架构组件库的实现细节。ViewModel由于调整用例以匹配s API公开的指南/合同,您很可能应该提出一个更好的解决方案。

尽管如此,让我们检查一下这样做的可能性。

这是代码,我们应该使用它来获得ViewModel实现:

val viewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)

这段代码的结果是,它将创建一个 的实例HolderFragment,这是一个保留的片段,并将其附加到this的片段管理器(可能是FragmentActivity的片段管理器或Fragment子片段管理器)。

HolderFragment将添加一个HolderFragment.HOLDER_TAG,因此我们能够从片段管理器中获取该片段的实例。

val holderFragment = supportFragmentManager.findFragmentByTag("android.arch.lifecycle.state.StateProviderHolderFragment") as HolderFragment

它是HolderFragment, 创建一个实例ViewModelStore并将该实例保存为私有字段。该字段存在 getter,但不存在 setter,这意味着“替换”该对象的唯一方法是使用反射。

但在此之前,让我们尝试编写ViewModelStore类的自定义实现:

class MyViewModelStore : ViewModelStore() {

  private val mMap = HashMap<String, ViewModel>()

  internal fun put(key: String, viewModel: ViewModel) {
    val oldViewModel = mMap.put(key, viewModel)
    oldViewModel?.onCleared() // COMPILATION ERROR -> Cannot access 'onCleared': it is protected/*protected and package*/ in 'ViewModel'
  }

  internal operator fun get(key: String): ViewModel? {
    return mMap[key]
  }

  override fun clear() {
    for (vm in mMap.values) {
      vm.onCleared() // COMPILATION ERROR -> Cannot access 'onCleared': it is protected/*protected and package*/ in 'ViewModel'
    }
    mMap.clear()
  }

}

不幸的是,我们不能这样做,因为ViewModel#onCleared() 有一个protected包访问权限,这使得我们无法在android.arch.lifecycle包之外调用它。同样,我们可以使用反射来做到这一点(但这有多好?)。

尽管(我)没有建议,但似乎也无法做到(不使用反射)。

于 2018-04-13T08:17:30.113 回答