What Is the Purpose of the TileRepository in Google Timeline Visualizer?
The TileRepository in Google Timeline Visualizer is a centralized caching and loading component that supplies map-tile images to the rendering pipeline, managing both in-memory LRU caching and persistent disk storage while fetching missing tiles from remote basemap services.
This core utility, found in TileRepository.kt, abstracts away the complexity of tile retrieval so that the visualizer's UI and export modules can render geographic backgrounds efficiently. According to the mahlernim/google-timeline-visualizer source code, the repository handles four critical responsibilities that enable smooth, flicker-free map visualization.
Core Responsibilities of the TileRepository
The TileRepository serves as the single source of truth for all map tile operations within the app. Its design separates concerns cleanly across caching, network I/O, key generation, and pipeline integration.
Cache Management
The TileRepository implements a two-tier caching strategy to minimize network requests and latency:
- Memory LRU cache: Stores recently accessed tiles in RAM for immediate retrieval during rapid scrolling or animation
- Disk persistence: Saves tiles to the app's cache directory (
cacheDirectory) so they survive process restarts and are available offline
This dual approach ensures that once a tile has been loaded once, subsequent requests resolve in milliseconds without touching the network.
Tile Loading from Remote Sources
When a requested tile is absent from both cache layers, the repository fetches it from the Carto basemap service at https://a.basemaps.cartocdn.com/.... The implementation follows a robust download pattern:
// Simplified flow from TileRepository.kt
withContext(Dispatchers.IO) {
val tempFile = File(cacheDirectory, "$key.tmp")
// Download to temporary location
downloadTile(url, tempFile)
// Atomic move prevents partial files
tempFile.renameTo(File(cacheDirectory, key))
}
Network operations run on the IO dispatcher, and the atomic file move guarantees cache integrity even if the download is interrupted.
Deterministic Key Generation
To ensure consistent cache hits, the TileRepository generates keys from TileId objects using a predictable format:
"${zoom}_${x}_${y}"
This string becomes both the memory cache key and the on-disk filename, mapping any geographic tile coordinates to exactly one storage location.
Integration with the Rendering Pipeline
The repository exposes two primary interfaces for consumers:
| Method | Purpose | Caller |
|---|---|---|
cached(tileId) |
Synchronous lookup from memory/disk | TimelineView, TimelinePainter, Mp4Exporter |
load(tileId) |
Suspending network fetch and cache write | Coroutines launched by TimelineView |
The TimelineView coordinates these calls: it first attempts tiles.cached(tileId), and if null, launches a coroutine to tiles.load(tileId) followed by markFrameDirty() to trigger redraw.
How the TileRepository Fits Into the Architecture
The repository sits between remote tile servers and three downstream consumers:
TimelineView Orchestration
In TimelineView.kt, the view acts as coordinator. During onDraw(), it passes a function reference to the painter:
painter.draw(
targetCanvas,
width,
height,
data,
animationFrame,
journeyDurationSeconds,
videoTitle,
renderText,
cameraSettings,
allowCameraTrackBuild = isCameraReady,
tiles = tiles::cached // cache lookup injected into renderer
)
This design lets the painter query tile availability synchronously during each frame without blocking on network I/O.
TimelinePainter Rendering
TimelinePainter.kt receives tiles::cached as a parameter. While drawing the map background, it invokes this function for every visible tile coordinate, skipping any tiles not yet available. This prevents frame drops—missing tiles simply render as blank or background color until the cache populates.
Mp4Exporter Video Generation
The export pipeline in Mp4Exporter.kt also relies on TileRepository. When generating video frames offline, it pre-fetches all required tiles via the same cached()/load() interface, ensuring the exported video contains complete map backgrounds without runtime network dependencies.
Practical Usage Example
The following pattern demonstrates typical tile acquisition in the visualizer:
val tileId = TileId(zoom = 4, x = 12, y = 9)
// Try memory or disk cache first
val cachedBitmap = tiles.cached(tileId)
// If not cached, load from network (suspend function)
if (cachedBitmap == null) {
scope.launch {
tiles.load(tileId) // downloads and caches the tile
markFrameDirty() // triggers a redraw once ready
}
}
This idiom appears throughout TimelineView.kt and Mp4Exporter.kt, with the coroutine scope tied to the component's lifecycle to prevent leaks.
Key Files and Their Relationships
| File | Path | Role |
|---|---|---|
TileRepository.kt |
app/src/main/java/dev/mahlernim/timelinevisualizer/data/TileRepository.kt |
Core implementation of caching, storage, and network loading |
TimelineView.kt |
app/src/main/java/dev/mahlernim/timelinevisualizer/ui/TimelineView.kt |
UI component that requests tiles and schedules redraws |
TimelinePainter.kt |
app/src/main/java/dev/mahlernim/timelinevisualizer/render/TimelinePainter.kt |
Renderer that queries cached tiles during frame drawing |
Mp4Exporter.kt |
app/src/main/java/dev/mahlernim/timelinevisualizer/export/Mp4Exporter.kt |
Video exporter that fetches tiles for offline frame generation |
Summary
-
The TileRepository centralizes all map tile operations in Google Timeline Visualizer, eliminating duplicate network requests and providing fast, consistent access to geographic imagery.
-
Its dual-layer caching (memory LRU plus disk persistence) optimizes for both speed and offline capability.
-
Deterministic key generation from
TileIdcoordinates ensures cache consistency across the codebase. -
The repository's synchronous
cached()and suspendingload()methods let UI and export consumers choose appropriate concurrency models. -
By shielding
TimelineView,TimelinePainter, andMp4Exporterfrom network details, the TileRepository enables smooth 60fps rendering and reliable video export regardless of connectivity conditions.
Frequently Asked Questions
What happens if a tile download fails in TileRepository?
Failed downloads do not cache partial data. The temporary file mechanism in TileRepository.kt writes to a .tmp file first, then atomically renames only on successful completion. If the network request throws, the temporary file is discarded and the next cached() call returns null, allowing retry on the next frame or export attempt.
How does TileRepository handle concurrent requests for the same tile?
The implementation uses Kotlin coroutines with structured concurrency. Multiple callers may simultaneously request the same uncached tile, but the disk write is atomic and idempotent—subsequent writes with identical content produce the same result. The memory cache absorbs redundant lookups once the first successful load completes.
Why does TimelinePainter use a function reference instead of direct TileRepository access?
Passing tiles::cached as a parameter decouples the renderer from data dependencies. This inversion of control lets TimelinePainter remain a pure rendering component while TimelineView manages lifecycle, threading, and cache invalidation. The same painter code works for both real-time preview and video export with different tile providers if needed.
Can TileRepository work with other basemap providers besides Carto?
The repository's design is provider-agnostic. The Carto URL is currently hardcoded, but the key generation and caching logic depend only on TileId coordinates. To support additional providers, one would modify the URL construction in load() without changing the cache layer or public interface.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →