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
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 @MapKey
s é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
.