Notas sobre dagger
Inyección de dependencias automatizada
Metaprogramación
La metaprogramación es un programa que trata a otros programas como sus datos, para agregar o cambiar el comportamiento y las funcionalidades.
La metaprogramación puede ocurrir en:
Tiempo de ejecución: Reflexión.
Tiempo de compilación: Generadores (anotaciones).
Opciones de biblioteca
Dagger: popular biblioteca de inyección de dependencias para Java, Kotlin y Android.
Hilt: la biblioteca recomendada de Jetpack para la inyección de dependencia en Android.
Dagger
Dagger es un marco de inyección de dependencias en tiempo de compilación totalmente estático para Java, Kotlin y Android. Es una adaptación de una versión anterior creada por Square y ahora mantenida por Google.
Dagger tiene como objetivo abordar muchos de los problemas de desarrollo y rendimiento que han plagado las soluciones basadas en la reflexión.
Beneficios
Dagger lo libera de escribir código repetitivo tedioso y propenso a errores al:
Generando el código (gráfico de dependencias la aplicación) que implementaste manualmente en la sección de inyección manual.
Creación de factorías para las clases disponibles. Así es como las dependencias se satisfacen internamente.
Decidir si reutilizar una dependencia o crear una nueva instancia mediante el uso de alcances.
Creación de contenedores para flujos específicos.
Dagger en acción
@Singleton
@Component(modules = [NetworkModule::class])
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): ApplicationComponent
}
fun repository(): UserRepository
fun inject(activity: LoginActivity)
}
@Module
class NetworkModule {
@Singleton
@Provides
fun provideLoginRetrofitService(): LoginRetrofitService { ... }
}
@Singleton
class UserRepository @Inject constructor(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) { ... }
class MyApplication : Application() {
val applicationComponent: ApplicationComponent by lazy {
initializeComponent()
}
private fun initializeComponent(): ApplicationComponent = DaggerApplicationComponent
.factory()
.create(applicationContext)
}
class LoginActivity : AppCompatActivity() {
@Inject lateinit var loginViewModel: LoginViewModel
...
override fun onCreate(savedInstanceState: Bundle?) {
(application as MyApplication).applicationComponent.inject(this)
super.onCreate(savedInstanceState)
...
}
}
- Anotación @BindsInstance
@Component(modules = [StorageModule::class])
interface ApplicationComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance context: Context): ApplicationComponent
}
}
Anotación @Inject
class RegistrationViewModel @Inject constructor(val userManager: UserManager) { ... }
Anotación @Binds
@Module abstract class StorageModule { @Binds abstract fun provideStorage(storage: SharedPreferencesStorage): Storage }
Anotación @Provides
@Module class StorageModule { @Provides fun provideStorage(context: Context): Storage { return SharedPreferencesStorage(context) } }
-
@Module abstract class ExampleModule { @Binds abstract fun bindsExampleClass(factory: ExampleClassImpl): ExampleClass companion object { @Provides fun provideExampleClass(): ExampleClass = ProvidedExampleClass() } }
Alcances personalizados
@Scope
@MustBeDocumented
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ActivityScope
@ActivityScope
@Subcomponent
interface RegistrationComponent { ... }
@ActivityScope
class RegistrationViewModel @Inject constructor(val userManager: UserManager) {
...
}
subcomponentes
@Subcomponent
interface RegistrationComponent {
@Subcomponent.Factory
interface Factory {
fun create(): RegistrationComponent
}
fun inject(activity: RegistrationActivity)
}
@Module(subcomponents = [RegistrationComponent::class])
class ApplicationSubcomponents
@Singleton
@Component(modules = [StorageModule::class, ApplicationSubcomponents::class])
interface applicationComponent {
...
fun registrationComponent(): RegistrationComponent.Factory
}
class RegistrationActivity : AppCompatActivity() {
...
override fun onCreate(savedInstanceState: Bundle?) {
registrationComponent = (application as MyApplication).applicationComponent.registrationComponent().create()
registrationComponent.inject(this)
super.onCreate(savedInstanceState)
...
}
...
}
Desafío
- Automatiza la inyección de dependencias en tu proyecto con dagger.