Я хочу иметь 2 разные реактивные реализации интерфейса, которые получают местоположение пользователя в другом модуле проекта в AndroidStudio.
Так что, если быть точным, это может быть с помощью gms или только с помощью родного Android LocationManager.
Вот мой интерфейс репозитория:
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 в gradle), а также нативную реализацию для другого модуля в 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
}
}
}
Он использует некий Dagger Component, который обеспечивает ему реализацию всех различных объектов. Итак, я хочу переместить этот LocationClient или сделать его абстрактным в модуле проекта location_core и переместить его реализацию в каждый модуль проекта location_gms и location_native в AndroidStudio.
Таким образом, класс LocationClient в каждом из них будет предоставлять различную реализацию этого RxRepository. На данный момент в каждом модуле проекта location_gms и location_native у меня есть только класс реализации, который реализует репозиторий rxLocationRepository (который я перемещаю из реализации, написанной выше) по-своему.
Проблема в том, что я точно не знаю, как управлять всем этим с помощью Dagger. Теперь я использую Dagger вот так в моем 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 с Dagger, чтобы я мог просто использовать интерфейс RxLocationRepository в моем модуле location_core и не беспокоиться о его реализации, потому что он будет в каждый модуль проекта?
Конечно, я должен отметить, что эти 3 модуля никогда не будут вместе, я думаю, это будет 2 модуля в каждом build_variant, я думаю. Поэтому мне нужно избавиться от зависимости от служб Google в модуле проекта location_core build.gradle.
ОБНОВЛЕНИЕ
Как я могу на самом деле не иметь компонента Dagger в моем location_core, в котором я использую его в тестах, таких как:
val component = DaggerLocationTestInstrumentalComponent.builder().context(InstrumentationRegistry.getContext()).build()
val database = component.testDatabase()
val locationManager = component.locationClient().nexoLocationManager