web-dev-qa-db-fra.com

Dague Android pour classe personnalisée possible?

J'essaie de faire fonctionner poignard Android avec Conductor (ou n'importe quelle classe personnalisée). J'ai essayé de répliquer tout ce que font AndroidSupportInjectionModule (et ses amis), ce qui, à mon sens, correspond au même type de traitement de classe personnalisé.

Cependant je reçois

C:\Users\ursus\AndroidStudioProjects\...\ControllersModule.Java:15: error: com.foo.bar.ChannelsController is not a framework type
    public abstract com.foo.bar.ChannelsController channelsController();

Donc, mon code "bibliothèque"

package com.foo.bar

import com.bluelinelabs.conductor.Controller;
import dagger.Module;
import dagger.Android.AndroidInjectionModule;
import dagger.Android.AndroidInjector;
import dagger.internal.Beta;
import dagger.multibindings.Multibinds;

import Java.util.Map;

@Beta
@Module(includes = AndroidInjectionModule.class)
public abstract class ConductorInjectionModule {

    private ConductorInjectionModule() {
    }

    @Multibinds
    abstract Map<Class<? extends Controller>, AndroidInjector.Factory<? extends Controller>> controllerInjectorFactories();

    @Multibinds
    abstract Map<String, AndroidInjector.Factory<? extends Controller>> controllerInjectorFactoriesWithStringKeys();
}

Je ne suis même pas compilé, donc supposer de coller ConductorInjection et HasControllerInjector est inutile

Usage:

@Module
abstract class AppModule {
    @ContributesAndroidInjector abstract fun mainActivity(): MainActivity
    @ContributesAndroidInjector abstract fun channelsController(): ChannelsController
}

class App : Application(), HasActivityInjector, HasControllerInjector {

    @Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity>
    @Inject lateinit var controllerInjector: DispatchingAndroidInjector<Controller>

    private lateinit var appComponent: AppComponent

    override fun onCreate() {
        super.onCreate()

        appComponent = DaggerAppComponent.builder()
            .applicationContext(this)
            .build()
            .apply {
                inject(this@App)
            }
    }

    override fun activityInjector() = activityInjector
    override fun controllerInjector() = controllerInjector
}

@Singleton
@Component(
    modules = [
        AndroidInjectionModule::class,
        ConductorInjectionModule::class,
        AppModule::class,
        NetModule::class
    ]
)
interface AppComponent {

    fun inject(app: App)

    @Component.Builder
    interface Builder {

        @BindsInstance
        fun applicationContext(context: Context): Builder

        fun build(): AppComponent
    }
}


implementation deps.dagger.runtime
implementation deps.dagger.androidRuntime
kapt deps.dagger.compiler
kapt deps.dagger.androidCompiler

où il est tout "2.19" version (ont essayé 2.16)

AGP "com.Android.tools.build:gradle:3.3.0-rc02" (ont essayé la version 3.2.1 stable)

Un indice? Dans mon esprit, tout devrait fonctionner comme c'est la même chose que dagger-Android-support fait

4
urSus

erreur: com.foo.bar.ChannelsController n'est pas un type de structure

La question à laquelle il faut répondre est donc: "Comment dagger-Android sait-il ou non un type de framework"?.

La réponse se trouve dans ce commit sur Dagger-Android entre 2.19 et 2.20, où ils "ont supprimé l'ancienne manière de faire les choses pour une meilleure compatibilité avec AndroidX".

Donc, comme on peut le voir dans https://stackoverflow.com/a/53891780/2413303

   /**    
    * Returns the Android framework types available to the compiler, keyed by their associated {@code 
    * dagger.Android} {@link MapKey}s. This will always contain the types that are defined by the 
    * framework, and only contain the support library types if they are on the classpath of the   
    * current compilation.    
    */    
   static ImmutableMap<Class<? extends Annotation>, TypeMirror> frameworkTypesByMapKey(   
       Elements elements) {   
     return ImmutableMap.copyOf(  
         Stream.of(   
                 elements.getPackageElement("dagger.Android"),    
                 elements.getPackageElement("dagger.Android.support"))    
             .filter(packageElement -> packageElement != null)    
             .flatMap(packageElement -> typesIn(packageElement.getEnclosedElements()).stream())   
             .filter(AndroidMapKeys::isNotAndroidInjectionKey)    
             .filter(type -> isAnnotationPresent(type, MapKey.class)) 
             .filter(mapKey -> mapKey.getAnnotation(MapKey.class).unwrapValue())  
             .flatMap(AndroidMapKeys::classForAnnotationElement)  
             .collect(toMap(key -> key, key -> mapKeyValue(key, elements)))); 
   }

ils avaient un code qui vérifiait leurs propres types @MapKey dans les packages dagger.Android et dagger.Android.support, qui ressemblait à ceci:

// Java/dagger/Android/support/FragmentKey.Java

 @Beta  
 @MapKey    
 @Documented    
 @Target(METHOD)    
 @Deprecated    
 public @interface FragmentKey {    
   Class<? extends Fragment> value();   
 }

Ils lisent donc les types de structure en fonction de ce que @MapKeys était disponible dans les packages dagger.Android et dagger.Android.support.


Apparemment, ils ont enlevé cette vérification en 2.20 afin que vous puissiez maintenant injecter ce que vous voulez. Réjouir!

Mais sinon, vous pourriez le pirater de manière à ajouter un paquet @ControllerKey et un paquet @ViewKey dans dagger.Android dans votre projet, et il fonctionnerait probablement avec la version 2.19.

Les tests qui cherchaient des erreurs dans "n'est pas un type de structure" sont également supprimés dans cette validation.

Une main 

@Multibinds
abstract Map<String, AndroidInjector.Factory<? extends Controller>> controllerInjectorFactoriesWithStringKeys();

Vous pouvez aussi supprimer cette partie avec 2.20, tout ce dont vous avez besoin maintenant est AndroidInjectionModule.

5
EpicPandaForce

Pour les futurs voyageurs, ils codaient en dur certaines informations de l'application dans l'annot. processeur, c’est pourquoi les fragments d’appcompat ont fonctionné.

 enter image description here

mettre à jour à la dague 2.20, cela fonctionnera comme par magie

1
urSus