Проблема
При попытке добавить связывание ViewModel
в мультисвязку для унаследованного ViewModelFactory
(созданного без области) в пределах нижней области (@FragmentScope
), я продолжаю сталкиваться с этим ошибка:
java .lang.IllegalArgumentException: неизвестный класс модели com.example.app.MyFragmentVM
Что я прочитал или попробовал
(примечание: приведенный ниже список ни в коем случае не является исчерпывающим, но представляет собой два хороших примера ресурсов и советы, которые я изучил)
Я относительно новичок в работе с Dagger, поэтому мне пришлось много гуглить, чтобы попытаться понять, что происходит, но я достиг точки, когда, насколько я понимаю, что-то должно работать (?). ..
Из источников, похожих на [1], я удалил область @Singleton
на ViewModelFactory
, но все еще получаю afor ementioned cra sh о том, что в отображении не найден класс моделей.
Из источников, похожих на [2], я попытался укрепить мое понимание того, как работают зависимости и как элементы подвергаются воздействию зависимых компонентов. Я знаю и понимаю, как ViewModelProvider.Factory
доступен для моих MyFragmentComponent
и связанных с ним модулей.
Однако я не понимаю, почему @Binds @IntoMap
не работает для MyFragmentVM
.
Код
Позвольте мне сначала go через настройку содержимого, которое уже существует в приложении - почти ни один из них не был определен для определенных c случаев
// AppComponent
@Component(modules=[AppModule::class, ViewModelModule::class])
interface AppComponent {
fun viewModelFactory(): ViewModelProvider.Factory
fun inject(activity: MainActivity)
// ... and other injections
}
// AppModule
@Module
class AppModule {
@Provides
@Singleton
fun providesSomething(): Something
// a bunch of other providers for the various injection sites, all @Singleton scoped
}
// ViewModelModule
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindsViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
@Binds
@IntoMap
@ViewModelKey(MainActivityVM::class)
abstract fun bindsMainActivityVM(vm: MainActivityVM): ViewModel
}
// VMFactory
class ViewModelFactory @Inject constructor(
private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
val creator = creators[modelClass] ?: creators.entries.firstOrNull {
modelClass.isAssignableFrom(it.key)
}?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
try {
@Suppress("UNCHECKED_CAST")
return creator.get() as T
} catch (e: Exception) {
throw RuntimeException(e)
}
}
}
И вот как я пытаюсь добавить и использовать свой @FragmentScope:
// MyFragmentComponent
@FragmentScope
@Component(
dependencies = [AppComponent::class],
modules = [MyFragmentModule::class, MyFragmentVMModule::class]
)
interface MyFragmentComponent {
fun inject(fragment: MyFragment)
}
// MyFragmentModule
@Module
class MyFragmentModule {
@Provides
@FragmentScope
fun providesVMDependency(): VMDependency {
// ...
}
}
// MyFragmentVMModule
@Module
abstract class MyFragmentVMModule {
@Binds
@IntoMap
@ViewModelKey(MyFragmentVM::class)
abstract fun bindsMyFragmentVM(vm: MyFragmentVM): ViewModel
}
// MyFragment
class MyFragment : Fragment() {
@set:Inject
internal lateinit var vmFactory: ViewModelProvider.Factory
private lateinit var viewModel: MyFragmentVM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DaggerMyFragmentComponent.builder()
.appComponent(MyApplication.instance.component)
.build()
.inject(this)
viewModel = ViewModelProvider(this, vmFactory).get(MyFragmentVM::class.java)
}
}
Здесь интересно отметить, что MyFragmentModule
сам НЕ в конечном итоге предоставляет какие-либо уникальные инъекции для MyFragment
(все они взяты из AppComponent, как сейчас). Тем не менее, он предоставляет уникальные инъекции для ViewModel
, который MyFragment
использует.