/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:

  1. 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_history table, which survives process death but no longer skips empty cells.
  2. 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.