我在ViewModel类初始化期间遇到了一个奇怪的问题。我认为代码是解释问题的最佳方法。

我的所有ViewModels在此之后都继承:

abstract class BaseViewModel : ViewModel() {
    internal var args: Bundle? = null
}

我有委托(delegate)为片段提供ViewModel,它会自动从片段中加载参数。
interface ViewModelFactoryProvider<VIEW_MODEL : BaseViewModel, BINDING : ViewDataBinding> : ReadOnlyProperty<ViewModelFragment<VIEW_MODEL, BINDING>, VIEW_MODEL> {

val viewModelFactory: ViewModelProvider.Factory

override fun getValue(thisRef: ViewModelFragment<VIEW_MODEL, BINDING>, property: KProperty<*>): VIEW_MODEL {
    return ViewModelProviders.of(thisRef, viewModelFactory).get(thisRef.viewModelClass).apply {
        thisRef.arguments?.let { thisRef.viewModel.args = it }
    }
  }
}

基本片段在上面实现接口(interface)并以这种方式创建 View 模型:
class ViewModelFragment<VIEW_MODEL : BaseViewModel, BINDING : ViewDataBinding> : Fragment(), ViewModelFactoryProvider<VIEW_MODEL, BINDING>{

    @Inject
    override lateinit var viewModelFactory: ViewModelProvider.Factory

    val viewModel: VIEW_MODEL by this
}

一切正常,直到ViewModel的片段没有任何其他参数为止,否则我得到:
 java.lang.StackOverflowError: stack size 8MB
    at android.support.v4.app.Fragment.getContext(Fragment.java:683)
    at android.support.v4.app.Fragment.getViewModelStore(Fragment.java:327)
    at android.arch.lifecycle.ViewModelStores.of(ViewModelStores.java:60)
    at android.arch.lifecycle.ViewModelProviders.of(ViewModelProviders.java:104)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:15)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$DefaultImpls.getValue(ViewModelFactoryProvider.kt:16)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getValue(ViewModelFragment.kt:20)
    at pl.kulbaka.karol.unilang.tools.ViewModelFragment.getViewModel(ViewModelFragment.kt)
    at pl.kulbaka.karol.unilang.tools.viewmodel.ViewModelFactoryProvider$

到目前为止,我不知道在哪里可以找到圆依存关系,这是什么原因。请帮忙。

最佳答案

这是由于在代理中计算thisRef.viewModel的值时访问viewModel引起的

您可以通过by this委派getViewModel()属性。即override fun getValue(..)方法使用代理的getViewModel()方法,该方法又在thisRef.viewModel.args = it中调用ViewModel。圆在该点重新开始。

你想要的大概是

override fun getValue(thisRef: ViewModelFragment<VIEW_MODEL, BINDING>, property: KProperty<*>): VIEW_MODEL {
    return ViewModelProviders.of(thisRef, viewModelFactory).get(thisRef.viewModelClass).apply {
        thisRef.arguments?.let { this.args = it }
    }
  }
}

它将参数设置在不是它试图创建的属性上,而是设置在从ViewModelProviders.of(...).get(...)返回的ojit_code上

09-25 21:03