Как реализовать репозиторий интерфейса в другом модуле проекта в AndroidStudio с помощью Dagger2 и Kotlin

Я хочу иметь 2 различных реактивной реализации интерфейса, который получает местоположение пользователя в другом модуле проекта в AndroidStudio.

Поэтому, чтобы быть конкретным, это может быть использование gms или только собственный локальный менеджер Android.

Вот мой интерфейс репозитория:

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

Итак, теперь я реализую этот интерфейс здесь, в классе, который находится в одном модуле проекта в 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 (ignored: IllegalArgumentException) { ignored.printStackTrace() } try { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, (geoEventsIntervalSeconds * 1000).toLong(), geoEventsDistanceMeters.toFloat(), mLocationCallbackNativeApi, Looper.getMainLooper()) } catch (ignored: IllegalArgumentException) { ignored.printStackTrace() } } @SuppressLint("MissingPermission") override fun onLocationUpdate(): Observable<Location> { return locationEmitter } override fun stopLocationUpdates() { if(isUsingLocationNativeApi) locationManager.removeUpdates(mLocationCallbackNativeApi) } } 

Итак, все в порядке, но теперь я хочу, чтобы реализация gms этого в разных модулях проекта (поэтому мне не нужно иметь зависимости gms в градиенте), а также встроенную реализацию для другого модуля в Android Studio.

Окончательная структура проекта в AndroidStudio будет похожа на location_core, location_gms, location_native.

Location_core не должен знать о location_gms и native, я думаю, в противоположность им – они будут иметь зависимость от location_core.

Итак, теперь у меня есть только проектный модуль location_core и класс LocationClient, который предоставит контекст:

 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 } } } 

Он использует какой-то компонент кинжала, который предоставляет ему всю реализацию разных объектов. Поэтому я хочу переместить этот LocationClient или сделать его абстрактным в модуле project_core project и перенести его реализацию в каждый модуль location_gms и location_native в AndroidStudio.

Таким образом, класс LocationClient в каждом из них обеспечит различную реализацию этого RxRepository. Пока что в каждом модуле location_gms и location_native project у меня есть только класс реализации, который реализует репозиторий rxLocationRepository (который я перехожу от реализации, написанной выше) по-своему.

Проблема в том, что я точно не знаю, как управлять всем этим с помощью кинжала. Теперь я использую кинжал, как это в моем location_core, вот 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 } } 

и его модуль:

 @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 } 

Итак, как написать фактический LocationClient в каждом из модулей – location_gms и location_native? Как обеспечить реализацию rxLocationRepository, который находится в каждом из модулей location_gms и location_native Project с Dagger, так что я могу просто использовать интерфейс RxLocationRepository в моем модуле location_core и не беспокоиться о его реализации, потому что он будет в каждый модуль проекта?

Конечно, я должен указать, что эти 3 модуля никогда не будут вместе, я думаю, это будет 2 модуля в каждом build_variant, я думаю. Поэтому мне нужно избавиться от зависимостей служб google в модуле проекта site_core build.gradle.

введите описание изображения здесь

ОБНОВИТЬ

Как я могу на самом деле не иметь компонент Dagger в моем location_core, в котором я использую его в тестах: val component = DaggerLocationTestInstrumentalComponent.builder().context(InstrumentationRegistry.getContext()).build() val database = component.testDatabase() val locationManager = component.locationClient().nexoLocationManager

Solutions Collecting From Web of "Как реализовать репозиторий интерфейса в другом модуле проекта в AndroidStudio с помощью Dagger2 и Kotlin"

Конечно, я должен указать, что эти 3 модуля никогда не будут вместе, я думаю, это будет 2 модуля в каждом build_variant, я думаю.

Это главное, чтобы обратить внимание. Определение вашего компонента не должно находиться внутри location_core . Вместо этого он должен быть на стороне потребителя. Потребителем я имею в виду модуль, который фактически использует местоположение. Назовем его consumer_module .

Как бы я подошел к этой задаче.

  1. И location_gms и location_native должны содержать LocationModule с различной реализацией. Используйте одно и то же имя пакета для LocationModule в обоих модулях.

  2. consumer_module содержит LocationComponent . В зависимости от варианта сборки он будет разрешен для LocationModule из location_gms или location_native .

Другой подход будет таким же для LocationModule , но создав в consumer_module два LocationComponent . Каждый в другом варианте сборки. В этом подходе вам не нужно сохранять одинаковое имя пакета для LocationModule .