Cómo implementar el repository de interfaz en otro module de proyecto en AndroidStudio usando Dagger2 y Kotlin

Quiero poder tener 2 implementaciones reactivas diferentes de la interfaz que obtiene la location del usuario en otro module de proyecto en AndroidStudio.

Para ser específico, puede ser mediante el uso de gms, o solo con LocationManager nativo de Android.

Aquí está mi interfaz de repository:

interface RxLocationRepository { @SuppressLint("MissingPermission") fun onLocationUpdate(): Observable<Location> fun stopLocationUpdates() } 

Así que por ahora, implemento esta interfaz aquí, en la class que está en el mismo module de proyecto en AndroidStudio:

 class RxLocationRepositoryImpl(val reactiveLocationProvider: ReactiveLocationProvider, val reactiveLocationRequest: LocationRequest, val isUsingLocationNativeApi: Boolean, val locationManager: LocationManager, val geoEventsDistanceMeters: Int, val geoEventsIntervalSeconds: Int ) : RxLocationRepository { var locationToPopulate: Location = Location(LocationManager.GPS_PROVIDER) lateinit var mLocationCallbackNativeApi: LocationListener private val subject: BehaviorSubject<Location> = BehaviorSubject.createDefault(locationToPopulate) var locationEmitter: Observable<Location> = subject.hide() init { configureEmitter() } @SuppressLint("MissingPermission") private fun configureEmitter(){ if (!isUsingLocationNativeApi) locationEmitter = reactiveLocationProvider.getUpdatedLocation(reactiveLocationRequest) else{ configureNativeLocationEmitter() } } @SuppressLint("MissingPermission") private fun configureNativeLocationEmitter() { mLocationCallbackNativeApi = object : LocationListener { override fun onLocationChanged(location: Location) { subject.onNext(location) } override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {} override fun onProviderEnabled(provider: String) {} override fun onProviderDisabled(provider: String) {} } try { locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, (geoEventsIntervalSeconds * 1000).toLong(), geoEventsDistanceMeters.toFloat(), mLocationCallbackNativeApi, Looper.getMainLooper()) } catch (ignonetworking: IllegalArgumentException) { ignonetworking.printStackTrace() } try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, (geoEventsIntervalSeconds * 1000).toLong(), geoEventsDistanceMeters.toFloat(), mLocationCallbackNativeApi, Looper.getMainLooper()) } catch (ignonetworking: IllegalArgumentException) { ignonetworking.printStackTrace() } } @SuppressLint("MissingPermission") override fun onLocationUpdate(): Observable<Location> { return locationEmitter } override fun stopLocationUpdates() { if(isUsingLocationNativeApi) locationManager.removeUpdates(mLocationCallbackNativeApi) } } 

Así que todo está bien, pero ahora quiero tener la implementación de gms de esto en un module de proyecto diferente (así que no necesito tener dependencies gms en el gradle) y también la implementación nativa del otro module en Android Studio.

La estructura final del proyecto en AndroidStudio será como location_core, location_gms, location_native.

El location_core no debe estar al tanto de location_gms y nativo, supongo que frente a ellos – tendrán la dependencia de location_core.

Así que ahora, ii solo tengo el module de proyecto location_core y una class LocationClient, que proporcionará el context:

 class LocationClient @Inject constructor(val nexoLocationManager: NexoLocationManager){ companion object { private var locationClient: LocationClient? = null fun obtainLocationClient(context: Context): LocationClient{ val result = locationClient ?: DaggerLocationComponent .builder() .context(context) .build() .locationClient() locationClient = result return result } } } 

Está utilizando algún Dagger Component, que le proporciona toda la implementación de diferentes objects. Por lo tanto, quiero mover este LocationClient o hacerlo abstracto en el module de proyecto location_core y mover la implementación del mismo en cada location_gms y module de proyecto location_native en AndroidStudio.

Entonces, la class LocationClient en cada uno de ellos proporcionará la implementación diferente de este RxRepository. Por ahora, en cada module de proyecto location_gms y location_native tengo solo una class de implementación que implementa el repository rxLocationRepository (que paso de la implementación escrita anteriormente) en su propio path.

El problema es que no sé exactamente cómo administrar todo esto con Dagger. Ahora estoy usando Dagger de esta manera en mi location_core, aquí está el LocationComponent:

 @Singleton @Component(modules = arrayOf(LocationModule::class)) interface LocationComponent{ fun locationClient(): LocationClient @Component.Builder interface Builder { @BindsInstance fun context(context: Context): Builder fun build(): LocationComponent } } 

y su module:

 @Module class LocationModule { //some stuff @Provides @Singleton fun providesRxLocationRepository( reactiveLocationProvider: ReactiveLocationProvider, reactiveLocationRequest: LocationRequest, @Named("CONFIG_LOCATION_USE_NATIVE_API")isUsingLocationNativeApi: Boolean, locationManager: LocationManager, @Named("CONFIG_LOCATION_GEO_EVENTS_DISTANCE_METERS")geoEventsDistanceMeters: Int, @Named("CONFIG_LOCATION_GEO_EVENTS_INTERVAL_SECONDS")geoEventsIntervalSeconds: Int ): RxLocationRepository = RxLocationRepositoryImpl( reactiveLocationProvider, reactiveLocationRequest, isUsingLocationNativeApi, locationManager, geoEventsDistanceMeters, geoEventsIntervalSeconds) //some other stuff } 

Entonces, ¿cómo escribir el LocationClient real en cada uno de los modules – location_gms y location_native? Cómo proporcionar la implementación del rxLocationRepository que está en cada uno de los modules location_gms y location_native project con Dagger, de modo que solo puedo usar la interfaz RxLocationRepository en mi module location_core y no me preocupo de su implementación, porque estará en cada module de proyecto?

Por supuesto, debo señalar que esos 3 modules nunca estarán juntos, supongo, serán 2 modules en cada build_variant, supongo. Así que tengo que deshacerme de la dependencia de los services de google en el module de proyecto de location_core build.gradle.

enter image description here

ACTUALIZAR

Cómo puedo realmente no tener el componente Dagger en mi location_core, en el que lo estoy usando en testings como: val component = DaggerLocationTestInstrumentalComponent.builder().context(InstrumentationRegistry.getContext()).build() val database = component.testDatabase() val locationManager = component.locationClient().nexoLocationManager

Por supuesto, debo señalar que esos 3 modules nunca estarán juntos, supongo, serán 2 modules en cada build_variant, supongo.

Ese es el punto principal para prestar atención. La definición de tu componente no debe estar dentro de location_core . En cambio, debe estar en el lado del "consumidor". Por consumidor, quiero decir adelante module que realmente usa la location. Llamémoslo consumer_module .

Cómo abordaría esta tarea.

  1. Tanto location_gms como location_native deberían contener LocationModule con una implementación diferente. Use el mismo nombre de package para LocationModule en ambos modules.

  2. consumer_module contiene LocationComponent . Según la variante de compilation, se resolverá en LocationModule desde location_gms o location_native .

Otro enfoque sería el mismo para LocationModule , pero creando en consumer_module dos LocationComponent . Cada uno en variante de compilation diferente. En ese enfoque, no es necesario que guarde el mismo nombre de package para LocationModule .

  • Escribir en el file después del partido en Kotlin
  • Obteniendo datos de local y remoto simultáneamente usando RxJava
  • ¿Por qué Smart-Cast no maneja esta situación?
  • constructor de class y variables miembro (campos)
  • Canal de puente a una secuencia
  • Kotlin: implementación LinkedList
  • Importación de jarras en kotlin REPL
  • ¿Cómo se manejan las properties anuladas en los bloques de inicio?
  • ¿Hay una sobrecarga para escribir una biblioteca en Kotlin para Android?
  • Cambios en el valor de ObservableField no propagados
  • ¿Puedo ejecutar kotlin como script con Java Scripting API