Dagger2, a adição de uma ligação para ViewModelProvider.Factory em um componente dependente

votos
0

O problema

Ao tentar adicionar um ViewModelligamento no MultiBinding para um herdado ViewModelFactory(criado sem escopo) dentro de um escopo menor ( @FragmentScope), eu continuo correndo para esse erro:

java.lang.IllegalArgumentException: com.example.app.MyFragmentVM classe de modelo desconhecido

O que eu li ou tentou

(Nota: o abaixo não é por qualquer meio uma lista exaustiva, mas são dois bons exemplos de recursos e os tipos de conselho que eu perused)

Eu sou relativamente novo para trabalhar com Dagger então eu tive que fazer um monte de pesquisando para tentar entender o que vem acontecendo, mas eu já chegou a um ponto em que, no meu entender, algo deve estar trabalhando (?) .. .

A partir de fontes semelhantes a [1], eu eliminou o @Singletonescopo de ViewModelFactory, mas eu ainda obter o acidente referido dizendo que não há classe de modelo encontrado no mapeamento.

A partir de fontes semelhantes a [2] Eu tentei reforçar a minha compreensão de como dependências funcionou e como os itens estão expostos a componentes dependentes. Eu sei e entender como ViewModelProvider.Factoryestá disponível para o meu MyFragmentComponente ele é relacionado Módulos.

No entanto, eu não entendo por que o @Binds @IntoMapnão está funcionando para o MyFragmentVM.

O código

Deixe-me ir primeiro através da configuração do material que já existe na aplicação - quase nada disso foi escopo para casos específicos

// 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 @Injects 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)
        }
    }
}

E o seguinte é como eu estou tentando adicionar e utilizar o meu @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)
    }
}

O que é interessante aqui para nota é que MyFragmentModuleem si não acabam fornecendo quaisquer injeções únicas para MyFragment(aqueles que vêm de todos AppComponent como é agora). Isto, contudo, fornecer injeções únicas para os ViewModelque MyFragmentusos.

Publicado 19/03/2020 em 21:51
fonte usuário
Em outras línguas...                            

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more