Open kmayoral opened 6 months ago
@kmayoral Thank you for opening this issue. 🙏 Please check out these other resources that might help you get to a resolution in the meantime:
google-maps
tagThis is an automated message, feel free to ignore.
Here could be an example implementation (untested):
package com.google.maps.android.rx
import com.google.android.gms.maps.GoogleMap
import com.google.maps.android.rx.shared.MainThreadObservable
import io.reactivex.rxjava3.core.Observable
import java.util.WeakHashMap
/**
* Utility class used to create shared observable instances that will be returned to callers for
* as long as the stream is active and the associated google map is still loaded in memory.
*
* @param initialCapacity should be set to a value greater than the max number of GoogleMap
* instances supported by the application. Defaults to 16 which should be more than enough for most
* use cases.
*/
public class SharedObservableCache<T : MainThreadObservable<R>, R : Any>(
initialCapacity: Int = 16,
) {
private val streamCache = WeakHashMap<GoogleMap, Observable<R>>(initialCapacity)
/**
* Returns an existing observable instance stored in the observable cache, if it exists or
* creates a new instance set to be removed from cache whenever the created observable is
* disposed, and then makes it shareable before placing it into the cache to be referenced by
* future callers.
*
* @param map The GoogleMap instance that we want to request event updates from
* @param creator The function to invoke to create a new event listening observable if none is
* present in the cache
* @return The shareable version of the created or cache referenced observable that is safe to
* reference across multiple callers
*/
public fun <T : Observable<R>> getOrCreate(map: GoogleMap, creator: (GoogleMap) -> T): Observable<R> {
return streamCache[map]
?: creator.invoke(map)
.doOnDispose { synchronized(streamCache) { streamCache.remove(map) } }
.share()
.also {
synchronized(streamCache) {
streamCache[map] = it
}
} as Observable<R>
}
}
And an example of how it could be referenced in an existing implementation such as within GoogleMapCameraIdleObservable.kt
:
// This is a static cache
private val sharedStreamCache by lazy {
SharedObservableCache<GoogleMapCameraIdleObservable, Unit>()
}
/**
* Creates an [Observable] that emits whenever the camera on this [GoogleMap] instance goes idle.
*
* The created [Observable] uses [GoogleMap.setOnCameraIdleListener] to listen to camera idle
* events. Since only one listener at a time is allowed, only one Observable at a time can be used.
*/
public fun GoogleMap.cameraIdleEvents(): Observable<Unit> =
GoogleMapCameraIdleObservable(this)
/**
* Retrieves a shared [Observable] that emits whenever the camera on this [GoogleMap] instance
* goes idle.
*
* The returned [Observable] will be an instance of [GoogleMapCameraIdleObservable] that has had
* {@link io.reactivex.rxjava3.core.Observable#share()} called on it in order to allow multiple
* concurrent rx streams to reference the same camera idle events.
*/
public fun GoogleMap.cameraIdleEventsShared(): Observable<Unit> =
sharedStreamCache.getOrCreate(this, GoogleMap::cameraIdleEvents)
private class GoogleMapCameraIdleObservable(
private val googleMap: GoogleMap
) : MainThreadObservable<Unit>() {
....
Thank you for this library!
A humble request to this update would be to provide a method to share a single observable instance across multiple callers for every map event type. This could be done by providing a wrapper around the googleMap instance that tracks the inner observable instance state or a static weakreference keyed-by-googlemap-instance type of cache that tracks any previously created observable instances to share out.
In this way, the caller can have multiple streams referencing the same underlying observables without worrying about that streams which were subscribed to earlier no longer receiving emissions.