Dagger 2 no puede inyectarse desde el subcomponente (kotlin)

Sé que, en general, no debería marcar la diferencia que esto esté usando Kotlin, pero me he encontrado con casos extraños en los que el calificador @Named necesitaba un scope en Kotlin tan simple conmigo.

Tengo una class ViewHolderFactory que me permite crear una asignación simple del tipo de vista -> ver class de titular:

 @Singleton class ViewHolderFactoryImpl @Inject constructor( private val viewHolderComponentProvider: Provider<ViewHolderSubcomponent.Builder> ): ViewHolderFactory(mapOf( R.layout.view_error to ErrorViewHolder::class.java, R.layout.view_soft_error to SoftErrorViewHolder::class.java, R.layout.view_empty to EmptyViewHolder::class.java, R.layout.view_loading to LoadingViewHolder::class.java, R.layout.item_got_it to GotItViewHolder::class.java)) { override fun createViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val viewHolder = super.createViewHolder(parent, viewType) if (viewHolder is Injectable) { viewHolderComponentProvider.get() .viewHolder(viewHolder) .build() .inject(viewHolder) } return viewHolder } } 

El componente ViewHolderSubcomponent se define a continuación, el objective es poder crear un subcomponente para cada titular de la vista e insert algunas cosas:

 @ViewHolderScope @Subcomponent(modules = [ViewHolderModule::class]) interface ViewHolderSubcomponent { fun inject(viewHolder: RecyclerView.ViewHolder) fun viewHolder(): RecyclerView.ViewHolder @Subcomponent.Builder interface Builder { @BindsInstance fun viewHolder(viewHolder: RecyclerView.ViewHolder): Builder fun build(): ViewHolderSubcomponent } } 

El ViewHolderModule se define como:

 @Module class ViewHolderModule { @Provides @ViewHolderScope fun provideSectionTitleViewHolder(viewHolder: RecyclerView.ViewHolder): SectionTitleViewHolder = SectionTitleViewHolder(viewHolder.itemView) } 

Cuando ejecuto la aplicación me parece que la inyección no funcionó, mis valores @Inject lateinit var son nulos. Al mirar el código generado puedo ver por qué:

 @Override public void inject(RecyclerView.ViewHolder viewHolder) { MembersInjectors.<RecyclerView.ViewHolder>noOp().injectMembers(viewHolder); } 

No hay MembersInjectors<RecyclerView.ViewHolder> creados para este subcomponente. No puedo entender cómo hacer que esto funcione. Sé que debería ser capaz de inyectar en objects no creados por daga, simplemente no puedo entender lo que me falta aquí.

Oh, si ayuda, me aseguré de include el ViewHolderSubcomponent en la list de subcomponents de mi AppModule

inject(viewHolder: RecyclerView.ViewHolder) siempre será no inject(viewHolder: RecyclerView.ViewHolder) , porque las classs de framework (o la mayoría de las bibliotecas en este caso) no tienen ningún campo @Inject anotado. Dagger solo generará código para la class nombrada en sus methods de inject(MyClass instance) , no para ninguno de sus subtypes .

Entonces, si tienes un ErrorViewHolder : RecyclerView.ViewHolder , entonces tienes que usar un componente que tenga un método de inject(ErrorViewHolder instance) para generar código para inyectar ErrorViewHolder .
Para aclarar, porque se genera código (y no reflection dynamic en el time de ejecución) invocando a llamada inject(viewHolder: RecyclerView.ViewHolder) como lo hace con un viewHolder : ErrorViewHolder intentará inyectar campos para RecyclerView.ViewHolder , no para ErrorViewHolder . Y RecyclerView.ViewHolder siempre será un no-operativo como se mencionó.

Tendrá que modificar bastante su configuration para poder proporcionar un subcomponente específico que pueda inyectar un visitante específico, no puede usar un componente "genérico" para diferentes types. Podría crear una class base entre RecyclerView.ViewHolder y ErrorViewHolder , pero de nuevo, solo podría inyectar campos declarados (y @Inject anotados) en su class base, no en el elemento secundario específico.

La propia propidad de Kotlin no es conocida por Dagger . Lo que está tratando de lograr podría manejarse como una inyección de campo o setter. Como un setter se genera con cualquier propiedad usualmente @set:Inject .

 @set:Inject lateinit var myVar: Type 

Alternativamente, puede considerar inyecciones de constructor. Así puedes definir las properties como val y privado.

  • ¿Cómo superar el error "la misma firma JVM" al implementar una interfaz Java?
  • División de routes en múltiples files
  • Accediendo a las properties de bean Java desde Kotlin
  • cómo establecer el color de RecyclerView.ViewHolder en BroadcastReceiver.onReceive?
  • Convención de encoding para funciones vacías que deben ser anuladas en Kotlin
  • ¿Cómo declaro una variable de tipo enum en Kotlin?
  • Utilice la unidad de Kotlin (o cualquier otro object) escriba en el layout de Android
  • ¿Cómo anular las properties de las classs de Java en Kotlin?
  • ¿Cómo usar la expresión Lamba para hacer que las llamadas al método Java sean less detalladas en Kotlin?
  • ¿Cómo unir dos tablas en Android usando el método de consulta del proveedor de contenido?
  • ¿Qué significa ". ()" En Kotlin?