Koin: получение экземпляра модели представления из родительского фрагмента с использованием интерфейса/абстрактного класса

Я объявил абстрактную модель представления (скажем, AnimalsViewModel), две модели представления расширяют ее (DogViewModel, CatViewModel).

соответствующие фрагменты (DogFragment, CatFragment) содержат общий фрагмент (AnimalFragment), которому нужен экземпляр того, что AnimalViewModel использует родительский фрагмент. Но как мне это получить AnimalFragment? Я попробовал это:

class AnimalFragment : Fragment() {

    private val viewModel by lazy {
            requireParentFragment().getViewModel<AnimalViewModel>()
    }
}

но это не работает, поскольку koin не находит экземпляр, принадлежащий родителю, и выдает ошибку, сообщающую, что он не находит поставщика для AnimalViewModel (очевидно, поскольку он абстрактный). Я пытался сделать это интерфейсом, но безрезультатно.

Есть ли способ добиться этого?

Обновлено: чтобы внести ясность, скажем, DogFragment имеет экземпляр DogViewModel с идентификатором 1 и CatFragment имеет CatViewModel с идентификатором 2, AnimalFragment внутри внутри DogFragment должен получить viewModel #1, а тот, что внутри CatFragment, должен получить #2. Проблема не в том, чтобы получить viewModel в правильной области, а в том, чтобы получить viewModel с использованием абстрактного класса в качестве идентификатора.

это работает отлично, но я не хочу добавлять параметр в AnimalFragment, чтобы знать, какую модель представления он должен запрашивать

private val viewModel by lazy {
        
            requireParentFragment().getViewModel<DogViewModel>()
     

    }

попробуйте сделать requireParentFragment().requireParentFragment(), как предложено здесь stackoverflow.com/questions/60356505/… и здесь medium.com/@kennethchangla/…

tyczj 29.04.2024 21:18

Я также видел by viewModels(ownerProducer = { requireParentFragment() }) использованный

tyczj 29.04.2024 21:22

@tyczj Я не думаю, что это проблема. AnimalFragment правильно запрашивает у своего родителя экземпляр viewModel, но не может его найти, поскольку я запрашиваю абстрактный класс. Если я укажу реализацию, которую хочу, она будет работать правильно

jack_the_beast 30.04.2024 09:25
0
3
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В итоге я определил интерфейс, который предоставляет модель представления требуемого абстрактного типа. Это не идеально, но лучше, чем передавать аргументы или упоминать родительские фрагменты в дочернем элементе.

interface AnimalContainer {
    abstract val viewModel: AnimalViewModel
}

class AnimalFragment : Fragment() {
    private val viewModel by lazy {
        (requireParentFragment() as? AnimalContainer)?.viewModel
            ?: error("AnimalFragment not allowed in container ${requireParentFragment()}")
    }
}

Другие вопросы по теме