# What Is the Purpose of the TileRepository in Google Timeline Visualizer?

> Discover the TileRepository's purpose in Google Timeline Visualizer. It efficiently caches and loads map tiles, improving performance for your visualizations.

- Repository: [mahlernim/google-timeline-visualizer](https://github.com/mahlernim/google-timeline-visualizer)
- Tags: internals
- Published: 2026-08-23

---

**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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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:

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

```kotlin
"${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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/TimelineView.kt), the view acts as coordinator. During `onDraw()`, it passes a function reference to the painter:

```kotlin
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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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:

```kotlin
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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/TimelineView.kt) and [`Mp4Exporter.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/TileRepository.kt) | [`app/src/main/java/dev/mahlernim/timelinevisualizer/data/TileRepository.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/app/src/main/java/dev/mahlernim/timelinevisualizer/data/TileRepository.kt) | Core implementation of caching, storage, and network loading |
| [`TimelineView.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/TimelineView.kt) | [`app/src/main/java/dev/mahlernim/timelinevisualizer/ui/TimelineView.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/app/src/main/java/dev/mahlernim/timelinevisualizer/ui/TimelineView.kt) | UI component that requests tiles and schedules redraws |
| [`TimelinePainter.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/TimelinePainter.kt) | [`app/src/main/java/dev/mahlernim/timelinevisualizer/render/TimelinePainter.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/app/src/main/java/dev/mahlernim/timelinevisualizer/render/TimelinePainter.kt) | Renderer that queries cached tiles during frame drawing |
| [`Mp4Exporter.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/Mp4Exporter.kt) | [`app/src/main/java/dev/mahlernim/timelinevisualizer/export/Mp4Exporter.kt`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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 `TileId` coordinates ensures cache consistency across the codebase.

- The repository's **synchronous `cached()` and suspending `load()` methods** let UI and export consumers choose appropriate concurrency models.

- By shielding `TimelineView`, `TimelinePainter`, and `Mp4Exporter` from 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`](https://github.com/mahlernim/google-timeline-visualizer/blob/main/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.