12 votes

Injection du champ de la poignée dans le super Fragment ou ViewModel

J'utilise Dagger-Hilt pour l'injection de dépendances dans mon projet Android. J'ai maintenant cette situation où j'ai un Fragment abstrait de base.

BaseViewModel.kt

abstract class BaseViewModel constructor(
    val api: FakeApi,
) : ViewModel() {

    //...

}

Ici, j'ai une dépendance qui est FakeApi . Ce que j'essaie de faire, c'est d'injecter l'élément FakeApi dans le BaseViewModel pour être disponible dans le BaseViewModel et tous ses enfants.

  • La première approche que j'ai essayé est d'utiliser l'injection du constructeur et de l'injecter dans l'enfant et de le passer au super en utilisant le constructeur.

TaskViewModel.kt

@HiltViewModel
class TaskViewModel @Inject constructor(
    api: FakeApi
) : BaseViewModel(api){

}

Cette approche fonctionne bien, mais je n'ai pas besoin de passer la dépendance de l'option child a la super j'ai besoin de la classe FakeApi pour être automatiquement injecté dans le BaseViewModel sans avoir à le passer car j'ai trois niveaux d'abstraction (il y a une autre classe qui hérite du TaskViewModel) Donc je dois le passer deux fois.

  • La deuxième approche consistait à utiliser l'injection sur le terrain de la manière suivante

BaseViewModel.kt

abstract class BaseViewModel: ViewModel() {
    @Inject
    lateinit var api: FakeApi
    //...
}

TaskViewModel.kt

@HiltViewModel
class TaskViewModel @Inject constructor(): BaseViewModel() {

}

Cette approche n'a pas fonctionné pour moi et les FakeApi n'a pas été injecté et j'ai une Exception

kotlin.UninitializedPropertyAccessException: lateinit property api has not been initialized

Mes questions sont les suivantes

  • Pourquoi l'injection de champ ne fonctionne pas pour moi ?
  • Existe-t-il un moyen d'utiliser l'injection de constructeur pour la fonction super au lieu de transmettre la dépendance de la classe child ?

5voto

Phan Van Linh Points 16963

J'ai testé et je vois que l'injection de champ dans base class fonctionne toujours avec Hilt 2.35. Je ne peux pas obtenir l'erreur comme vous, alors peut-être que vous pouvez essayer de changer la version de Hilt ou de vérifier comment vous fournissez FakeApi

abstract class BaseViewModel : ViewModel() {

    @Inject
    protected lateinit var fakeApi: FakeApi
}

FakeApi

// Inject constructor also working
class FakeApi {

    fun doSomeThing() {
        Log.i("TAG", "do something")
    }
}

MainViewModel

@HiltViewModel
class MainViewModel @Inject constructor() : BaseViewModel() {

    // from activity, when I call this function, the logcat print normally 
    fun doSomeThing() {
        fakeApi.doSomeThing()
    }
}

AppModule

@Module
@InstallIn(SingletonComponent::class)
class AppModule {

    @Provides
    fun provideAPI(
    ): FakeApi {
        return FakeApi()
    }
}

https://github.com/PhanVanLinh/AndroidHiltInjectInBaseClass

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X