/tripkit/TripKitData/com.skedgo.tripkit.data.locations/LocationsFetchCoordinator
LocationsFetchCoordinator
\ class LocationsFetchCoordinator(ttlMs: Long = DEFAULT_TTL_MS, clock: () -> Long = { System.currentTimeMillis() })
Coordinates calls to POST /satapp/locations.json made via StopsFetcher.
Two responsibilities:
- Recently-fetched tracking — a per-cell, in-memory timestamp of when we last successfully completed a fetch for that cell/region/level combination. While the timestamp is within ttlMs the cell is treated as "fresh" and excluded from the next request, so a small camera pan inside an already-loaded area does not re-hit the API. This works together with the persisted
scheduled_stops_download_historytable, which survives process death but no longer skips empty cells. - In-flight de-duplication — when multiple paths (viewport pipeline + prefetch + UI callback) trigger the same request key concurrently, only the first network call goes out; the rest share its result. This is critical because com.skedgo.tripkit.ui.map.home.MapViewModel routinely fires a main fetch and a buffered prefetch within milliseconds of each other.
Designed to be a process-scoped singleton (provided via Dagger).
Constructors
| LocationsFetchCoordinator | constructor(ttlMs: Long = DEFAULT_TTL_MS, clock: () -> Long = { System.currentTimeMillis() }) |
Types
| Name | Summary |
|---|---|
| Companion | object Companion |
Functions
| Name | Summary |
|---|---|
| filterStaleCellIds | fun filterStaleCellIds(cellIds: Collection<String>, regionName: String, level: Int): List<String> Returns the subset of cellIds that were NOT successfully fetched within the TTL window. Callers should only request these cell ids from the network. |
| hasInFlight | fun hasInFlight(key: String): Boolean |
| recordFetched | fun recordFetched(cellIds: Collection<String>, regionName: String, level: Int) Marks cellIds as successfully fetched at now. Called after a response is received, regardless of whether the cells came back with data — empty responses must be recorded too so sparse areas (e.g. AU_NT_Darwin grid cells with no stops) stop being re-fetched on every viewport change. |
| shareInFlight | fun shareInFlight(key: String, block: () -> Observable<List<LocationsResponse.Group>>): Observable<List<LocationsResponse.Group>> Runs block under an in-flight guard keyed by key. If another subscriber is already waiting on the same key, they share the same underlying network call. |