He sido Daga con la pre estilo Android inyector por un tiempo, y ahora han decidido probar los nuevos métodos. Hasta ahora, estaba básicamente declarando en AppComponent
este aspecto:
@Singleton
@Component(
modules = [ApplicationModule::class,
NetModule::class,
ApiModule::class,
AnalyticsModule::class,
DbModule::class,
RepositoryModule::class,
InteractorModule::class]
)
interface ApplicationComponent {
fun inject(app: MyApp)
fun plus(controllerModule: ControllerModule): ControllerComponent
}
Entonces me inyecte mi Activities
/ Fragments
/ Services
/ Dialogs
como esto:
class MyActivity : AppCompatActivity() {
...
val component by lazy {
(application as MyApp)
.applicationComponent
.plus(
ControllerModule(this)
)
}
override fun inject() {
component.inject(this)
}
...
}
Básicamente que tenía un componente superior nivel de aplicación con módulos app-de recorrido, a continuación, un componente de nivel de actividad ( ControllerComponent
) con instancias por-actividad, común a todas las actividades.
Ahora que me pasa a los nuevos métodos, creo mi componente de este modo:
@Singleton
@Component(
modules = [
AndroidSupportInjectionModule::class,
AppModule::class,
NetModule::class,
ApiModule::class,
AnalyticsModule::class,
DbModule::class,
RepositoryModule::class,
InteractorModule::class
]
)
interface AppComponent : AndroidInjector<SoulpicksApp> {
@Component.Builder
interface Builder {
fun build(): AppComponent
@BindsInstance
fun application(application: SoulpicksApp): Builder
}
}
Hacer que mi aplicación se extiende DaggerApplication
:
open class MyApp : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication> = DaggerAppComponent.builder().application(this).build()
}
Y mi Activities
/ Fragments
extender DaggerAppCompatActivty
/ DaggerFragment
respectivamente:
class MyActivity : DaggerAppCompatActivity() {
...
}
Entiendo que esto se debe conectar automáticamente todas las dependencias actividades, siempre Daga está configurado correctamente. Sin embargo havent de I mis declaró ControllerModule
/ Component
así que por supuesto cuando se ejecuta mi aplicación me sale:
e: /Users/user/dev/my-android/app/build/generated/source/kapt/devDebug/com/myapp/android/di/activity/ActivityBinder_ContributesMyActivity.java:28: error: @Subcomponent.Builder is missing setters for required modules or subcomponents: [com.myapp.android.di.controller.ControllerModule]
Tengo entendido previamente que estaba creando este componente en cada uno Activity
utilizando el método más () e inyectar de forma explícita (que es lo que estoy tratando de evitar aquí), ¿cómo puedo hacer eso ahora?
Además, tengo algunos BottomSheetDialogFragments
y JobServiceIntents
en mi aplicación, y theres ningún equivalente DaggerBottomSheedDialogFragments
/ DaggerJobServiceIntents
a extenderse desde, ¿cómo puedo evitar eso?
ControllerModule:
@Module
class ControllerModule(val activity: androidx.fragment.app.FragmentActivity) {
@Provides
@ControllerScope
fun context(): Context = activity
@Provides
@ControllerScope
fun activity() = activity
@Provides
@ControllerScope
fun layoutInflater() = activity.layoutInflater
@Provides
@ControllerScope
fun fragmentManager(): androidx.fragment.app.FragmentManager = activity.supportFragmentManager
@Provides
@ControllerScope
fun provideNavigationController(activity: androidx.fragment.app.FragmentActivity, analyticsManager: AnalyticsCompositeManager) = NavigationController(activity, analyticsManager)
@Provides
@ControllerScope
fun providePackageUtils(activity: androidx.fragment.app.FragmentActivity) : PackageUtils = PackageUtilsImpl(activity)
}
Los cambios después de @luis_cortes responden:
paquete io.soulpicks.android.di.activity
@Module
abstract class ActivityBinder {
@ControllerScope
@ContributesAndroidInjector(modules = [ControllerModule::class])
abstract fun constributesSplashActivity(): SplashActivity
@ControllerScope
@ContributesAndroidInjector(modules = [ControllerModule::class])
abstract fun contributesDashboardActivity(): DashboardActivity
....
}
ControllerModule:
@Module(includes = [ViewContainerModule::class])
class ControllerModule {
@Provides
@ControllerScope
fun context(activity: DaggerAppCompatActivity): Context = activity.applicationContext
@Provides
@ControllerScope
fun layoutInflater(activity: DaggerAppCompatActivity) : LayoutInflater = activity.layoutInflater
@Provides
@ControllerScope
fun fragmentManager(activity: DaggerAppCompatActivity): FragmentManager = activity.supportFragmentManager
@Provides
@ControllerScope
fun navigationController(activity: DaggerAppCompatActivity, analyticsManager: AnalyticsCompositeManager): NavigationController = NavigationController(activity, analyticsManager)
@Provides
@ControllerScope
fun providePackageUtils(activity: DaggerAppCompatActivity): PackageUtils = PackageUtilsImpl(activity)
}
Error:
e: /Users/kelmer/dev/myapp-android/app/build/tmp/kapt3/stubs/devDebug/io/myapp/android/di/application/AppComponent.java:8: error: [Dagger/MissingBinding] com.myapp.android.managers.PackageUtils cannot be provided without an @Provides-annotated method.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.myapp.android.MyApp> {
^
com.myapp.android.managers.PackageUtils is injected at
com.myapp.android.ui.invite.SendInviteViewModel(packageUtils, …)
com.myapp.android.ui.invite.SendInviteViewModel is injected at
com.myapp.android.di.viewmodel.ViewModelModule.sendInviteViewModel$app_devDebug(sendInviteViewModel)
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.myapp.android.di.viewmodel.MyappViewModelFactory(viewModels)
com.myapp.android.di.viewmodel.MyappViewModelFactory is injected at
com.myapp.android.di.viewmodel.ViewModelModule.bindViewModelFactory$app_devDebug(factoryMyapp)
androidx.lifecycle.ViewModelProvider.Factory is injected at
com.myapp.android.base.BaseActivity.viewModelFactory
com.myapp.android.ui.splash.SplashActivity is injected at
dagger.android.AndroidInjector.inject(T) [com.myapp.android.di.application.AppComponent → com.myapp.android.di.activity.ActivityBinder_ConstributesSplashActivity.SplashActivitySubcomponent]
It is also requested at:
com.myapp.android.ui.dashboard.friends.contact.ContactSyncViewModel(…, packageUtils, …)
com.myapp.android.views.appchoosedialog.AppChooserViewModel(packageUtils)
The following other entry points also depend on it:
dagger.android.AndroidInjector.inject(T) [com.myapp.android.di.application.AppComponent → com.myapp.android.di.activity.ActivityBinder_ContributesDashboardActivity.DashboardActivitySubcomponent]
https://github.com/kelmer44/mvvm-base
rama master
es la implementación actual (sin daga-androide) rama chore/dagger-rework
es mi intento
Actualizar
Me las arreglé para conseguir el proyecto de ejemplo se trabaja con algunos ajustes muy menores en la solución original. He actualizado la respuesta a continuación para la posteridad y pasos que son nuevos o han cambiado en negrita marcado.
Nota: Hubo algunos muy pequeños ajustes necesarios a la ControllerModule
en el proyecto de ejemplo que también eran necesarias, pero las respuestas a continuación son lo que sería más aplicable a todos los demás en el sitio, así que elegimos para omitir aquí.
- Crear un archivo llamado
MainActivityModule
con esto en él:
@Module
abstract class MainActivityModule {
@Binds @ControllerScope
abstract fun bindsActivity(mainActivity: MainActivity): FragmentActivity
}
- Agregue esto a un módulo que se instala en su AppComponent:
@ContributesAndroidInjector([ControllerModule::class, MainActivityModule::class])
@ControllerScope
abstract fun contributesMyActivity(): MyActivity
Retire
val activity: androidx.fragment.app.FragmentActivity
como una propiedad del constructor paraControllerModule
Cambiar los
@Provides
métodos para tomar en unaFragmentActivity
como esta:
@Provides
@ControllerScope
fun providesContext(activity: FragmentActivity): Context = activity
Para sus otras clases, sólo depende de si está o no controlar cuándo y cómo consiguen instanciado. Si lo hace, sólo tiene que utilizar la inyección de constructor regular.