StackOverflowError при инициализации ViewModel - PullRequest
0 голосов
/ 19 октября 2018

Я столкнулся со странной проблемой во время инициализации класса ViewModel.Я полагаю, что код - лучший способ объяснить проблему.

Мои все ViewModel наследуются после этого:

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

У меня есть делегат для предоставления 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 }
    }
  }
}

Базовый фрагмент реализует интерфейс выше и создает модель представления следующим образом:

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$

Пока я понятия не имею, где я могу найти зависимость от круга и в чем причина этого.Помогите пожалуйста.

1 Ответ

0 голосов
/ 19 октября 2018

Это вызвано доступом к thisRef.viewModel при расчете его значения в делегате

Вы делегируете свойство viewModel через by this.Т.е. метод getViewModel() использует метод override fun getValue(..) делегата, который в свою очередь вызывает getViewModel() in thisRef.viewModel.args = it.В этот момент круг перезапускается.

То, что вы хотите, примерно равно

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 }
    }
  }
}

, которое задает аргументы не для свойства, которое он пытается создать, а для ViewModel, возвращаемого из ViewModelProviders.of(...).get(...)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...