> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/android/navigation/llms.txt)

# Offline

There are two main kinds of offline functionality: predictive caching and offline regions. Predictive caching is fully automatic and based on the driver's behavior. It allows offline navigation around the user's current location, the destination, and the route itself. Offline regions need to be created and loaded ahead of time, enabling routing functionality in non-connected environments.

## Predictive caching

To use predictive caching, initialize a [`PredictiveCacheController`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/ui-maps/com.mapbox.navigation.ui.maps/-predictive-cache-controller/) using a [`MapboxNavigation`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core/-mapbox-navigation/) instance and [`PredictiveCacheOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-options/). You can also optionally configure `PredictiveCacheOptions` with [`PredictiveCacheMapsOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-maps-options/), [`PredictiveCacheNavigationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-navigation-options/), and [`PredictiveCacheSearchOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-search-options/). Once it's configured, the Navigation SDK will automatically create caches and make them available to the user. Note that the lifecycle of the `MapboxNavigation` instance must exceed that of the `PredictiveCacheController`, in particular, `MapboxNavigation` should not be destroyed while the `PredictiveCacheController` is still in use.

```kotlin
val predictiveCacheOptions = PredictiveCacheOptions.Builder()
    .predictiveCacheNavigationOptions(predictiveCacheNavigationOptions)
    .predictiveCacheMapsOptionsList(predictiveCacheMapsOptionsList)
    .predictiveCacheSearchOptionsList(predictiveCacheSearchOptionsList)
    .build()

val predictiveCacheController = PredictiveCacheController(mapboxNavigation, predictiveCacheOptions)
```

### Caching Navigation Data and ADAS

Navigation data caching is turned on by default when you initialize the `PredictiveCacheController`. You can customize and override the default parameters using [`PredictiveCacheNavigationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-navigation-options/). For example, you can change the dataset name and version, or enable ADAS data caching:

```kotlin
val predictiveCacheNavigationOptions = PredictiveCacheNavigationOptions.Builder()
    .tilesConfiguration(
        tilesDataset = tilesDataset,
        tilesVersion = tilesVersion,
        includeAdas = true,
    )
    // other options
    .build()
```

### Caching Map Data

To start caching map data, call [`createStyleMapControllers`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/ui-maps/com.mapbox.navigation.ui.maps/-predictive-cache-controller/create-style-map-controllers.html) with a `MapboxMap` instance and, optionally, pass a list of style URI to cache. Styles must be hosted on Mapbox, and URI must start with `“mapbox://”` (for example, `“mapbox://mapbox.mapbox-terrain-v2”`). If you do not pass any styles to `createStyleMapControllers`, current map's style will be cached.

```kotlin
// cache only passed styles for the mapboxMap instance
val stylesToCache: MutableList<String> = ArrayList()
stylesToCache.add("mapbox://mapbox.mapbox-terrain-v2")
val cacheCurrentStyle = false
predictiveCacheController.createStyleMapControllers(mapboxMap, cacheCurrentStyle, stylesToCache)

// cache current style for the anotherMapboxMap instance
predictiveCacheController.createStyleMapControllers(anotherMapboxMap)
```

### Caching Search Data

You can configure Predictive Cache to work with [`Mapbox Offline Search SDK`](https://docs.mapbox.com/android/search/guides/search-engine/offline/) to cache search data. To begin caching search data, integrate the [`Offline Search SDK`](https://docs.mapbox.com/android/search/guides/search-engine/offline/#integration-guide) and create a [`TilesetDescriptor`](https://docs.mapbox.com/android/search/guides/search-engine/offline/#define-a-tileset-descriptors-and-load-tile-regions) instance for the dataset you want to include in the cache, for example:

```kotlin
val tilesetDescriptor = OfflineSearchEngine.createTilesetDescriptor(dataset, version)
```

Next, pass the created `TilesetDescriptor` to [`PredictiveCacheSearchOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-search-options/)

```kotlin
val predictiveCacheSearchOptions = PredictiveCacheSearchOptions.Builder(tilesetDescriptor)
    .predictiveCacheLocationOptions(locationOptions)
    .build()

val predictiveCacheOptions = PredictiveCacheOptions.Builder()
    .predictiveCacheSearchOptionsList(
        listOf(predictiveCacheSearchOptions)
    )
    // other options
    .build()

// Provide predictiveCacheOptions to PredictiveCacheController
```

Once configured, Predictive Cache will automatically cache search data for you.

### Lifecycle

The controller and its [`MapboxNavigation`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core/-mapbox-navigation/) instance have a different lifecycle than the [`MapboxMap`](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps/-mapbox-map/) instance, so make sure to call [`removeMapControllers`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/ui-maps/com.mapbox.navigation.ui.maps/-predictive-cache-controller/remove-map-controllers.html) whenever the [`MapView`](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.maps/-map-view/) is destroyed to avoid leaking references or downloading unnecessary resources.

**Java**

```java

predictiveCacheController.removeMapControllers(mapboxMap);
```

**Kotlin**

```kt

predictiveCacheController.removeMapControllers(mapboxMap)
```

When the navigation session is finished and predictive caching is no longer needed, call `onDestroy` to remove all map and navigation references.

**Java**

```java

@Override
protected void onDestroy() {
    predictiveCacheController.onDestroy();
    mapView.onDestroy();
    mapboxNavigation.onDestroy();
    super.onDestroy();
}
```

**Kotlin**

```kt

override fun onDestroy() {
    predictiveCacheController.onDestroy()
    mapView.onDestroy()
    mapboxNavigation.onDestroy()
    super.onDestroy()
}
```

### Configure predictive caching

When predictive caching is enabled, the Navigation SDK will create a cache of data within three configurable boundaries from [`PredictiveCacheLocationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-location-options/) (passed via [`PredictiveCacheNavigationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-navigation-options/)):

1.  **Radius around the user's location**. Defaults to 20,000 meters. Use [`currentLocationRadiusInMeters`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-location-options/current-location-radius-in-meters.html) to configure this value.
2.  **Buffer around the route**. Defaults to 5,000 meters. Use [`routeBufferRadiusInMeters`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-location-options/route-buffer-radius-in-meters.html) to configure this value.
3.  **Radius around the destination**. Defaults to 50,000 meters. Use [`destinationLocationRadiusInMeters`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-location-options/destination-location-radius-in-meters.html) to configure this value.

To configure predictive caching, pass values, in meters, to any of the [`PredictiveCacheLocationOptions`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/base/com.mapbox.navigation.base.options/-predictive-cache-location-options/).

**Java**

```java

PredictiveCacheLocationOptions predictiveCacheLocationOptions = new PredictiveCacheLocationOptions.Builder()
    .currentLocationRadiusInMeters(1000)
    .routeBufferRadiusInMeters(2000)
    .destinationLocationRadiusInMeters(3000)
    .build();

PredictiveCacheNavigationOptions predictiveCacheNavigationOptions = new PredictiveCacheNavigationOptions.Builder()
    .predictiveCacheLocationOptions(predictiveCacheLocationOptions)
    .build();

PredictiveCacheOptions predictiveCacheOptions = new PredictiveCacheOptions.Builder()
    .predictiveCacheNavigationOptions(predictiveCacheNavigationOptions)
    .build();

PredictiveCacheController predictiveCacheController = new PredictiveCacheController(predictiveCacheOptions);
```

**Kotlin**

```kt

val predictiveCacheLocationOptions = PredictiveCacheLocationOptions.Builder()
    .currentLocationRadiusInMeters(1000)
    .routeBufferRadiusInMeters(2000)
    .destinationLocationRadiusInMeters(3000)
    .build()

val predictiveCacheNavigationOptions = PredictiveCacheNavigationOptions.Builder()
    .predictiveCacheLocationOptions(predictiveCacheLocationOptions)
    .build()

val predictiveCacheOptions = PredictiveCacheOptions.Builder()
    .predictiveCacheNavigationOptions(predictiveCacheNavigationOptions)
    .build()

val predictiveCacheController = PredictiveCacheController(predictiveCacheOptions)
```

`TileStore` handles offline regions data for both navigation and maps. By default, there is no limit to the size of a tile store. A quota can be configured with the `TileStoreOptions.DISK_QUOTA` option.

`TileStore` will refuse to store new data on disk if it would cause the quota to be exceeded. To make room for new content, tiles packs with the nearest expiration dates that aren't shared by another tile region will be removed before the quota is reached. By default, the eviction threshold is 50 MB or 10% of the `TileStoreOptions.DISK_QUOTA` (whichever is smaller). If your disk quota is 100 MB then eviction threshold will be 10 MB (it will try to keep `TileStore` size < 90 MB). And if the disk quota is 10 GB then default eviction threshold is 50 MB.

For instance, if you set `TileStoreOptions.DISK_QUOTA` to 600 MB then nothing will be removed until the tile store size reaches 550 MB. After that, tile store will start evicting tile packs with the nearest expiration date which are not part of any region to try to keep the size under 550 MB. In case all tile packs belong to some region and nothing can be evicted, tile store may keep growing and use the entire quota of 600 MB. After that no new tile packs can be added to the tile store and some regions would need to be removed or `TileStoreOptions.DISK_QUOTA` would need to be increased.

**Java**

```java

TileStore tileStore = TileStore.create();
tileStore.setOption(TileStoreOptions.DISK_QUOTA, new Value(600 * 1024 * 1024));
```

**Kotlin**

```kt

val tileStore = TileStore.create()
tileStore.setOption(TileStoreOptions.DISK_QUOTA, Value(600 * 1024 * 1024))
```

### Estimate predictive caching data use

Data usage depends on the configured radius and on map style. For the Mapbox Streets style, cache size is:

-   Berlin, 15km radius: 136 MB maps, 42 MB navigation
-   Chicago, 15km radius: 74 MB maps, 43 MB navigation
-   London, 15km radius: 145 MB maps, 90 MB navigation
-   Atlanta, 100 miles radius: 659 MB maps, 156 MB navigation

## Offline regions

`TileStore` allows users to create and download offline regions ahead of time, enabling routing functionality in non-connected environments. In areas with no cellular connectivity, or on a device with no SIM card, your users can use turn-by-turn navigation and request new routes. If they go off-route, the system can reroute and keep them headed to their destination without requiring network connectivity. `TileStore` copies the routing data from the server onto the user's device, so there's no need to make HTTP API calls for routing information.

> **Note: TileStore and the Maps SDK**
> 
> `TileStore` handles offline regions data for both navigation data for generating routes and map tiles for displaying a map in your application. Find more details on how to use `TileStore` for map data in the [Maps SDK documentation](https://docs.mapbox.com/android/navigation/guides/advanced/offline/).

### Initialize `TileStore` instance

To initialize a `TileStore` instance, provide a path to a cache directory where tiles will be stored.

**Java**

```java

TileStore tileStore = TileStore.create("path/to/cache/directory/");
```

**Kotlin**

```kt

val tileStore = TileStore.create("path/to/cache/directory/")
```

### Pass `TileStore` instance to maps and navigation

After the `TileStore` instance is initialized, pass it to both `MapboxNavigation` and `MapView` via the corresponding options.

> **Note**
> 
> For both offline and predictive-caching use cases, you must pass the same `TileStore` instance to the Maps SDK's `ResourceOptions` and the Navigation SDK's `RoutingTilesOptions`. This will guarantee the same tile regions will be used for both maps-related and navigation-related data.

Pass the `TileStore` instance to `RoutingTilesOptions` options and pass those options to `NavigationOptions` to be applied to the `MapboxNavigation` object:

**Java**

```java

RoutingTilesOptions routingTilesOptions = new RoutingTilesOptions.Builder()
    .tileStore(tileStore)
    .build();

NavigationOptions navOptions = new NavigationOptions.Builder(context)
    .routingTilesOptions(routingTilesOptions)
    .build();

MapboxNavigation mapboxNavigation = MapboxNavigationProvider.create(navOptions);
```

**Kotlin**

```kt

val routingTilesOptions= RoutingTilesOptions.Builder()
    .tileStore(tileStore)
    .build()

val navOptions = NavigationOptions.Builder(context)
    .routingTilesOptions(routingTilesOptions)
    .build()

val mapboxNavigation = MapboxNavigationProvider.create(navOptions)
```

Pass the `TileStore` instance to `MapboxMapsOptions` options to be applied to the `MapView` object:

**Java**

```java

MapboxMapsOptions.setTileStore(tileStore);
```

**Kotlin**

```kt

MapboxMapsOptions.tileStore = tileStore
```

### Download a tile region

To load a new tile region or update an existing one, create an asynchronous tile region download by calling the tile store's `loadTileRegion` method and passing in the `TileRegionLoadOptions`.

To create a **new tile region**, start by defining `TileRegionLoadOptions`. You must provide at least two pieces of information to `TileRegionLoadOptions`:

-   `geometry`: `GeoJson` object describing some area (for example `Polygon` or `MultiPolygon`).
-   `descriptors`: tileset descriptor is a bundle that encapsulates tilesets creation for the tile store implementation. Maps tileset descriptor contains metadata about the tilesets, zoom ranges, and pixel ratio that cached tile packs should include. Navigation tileset descriptor contains version of the navigation tiles that cached tile packs should include.

If one or both pieces of information are missing, the load request will fail with `RegionNotFound` error.

To begin loading the new tile region, pass the options to `loadTileRegion`. Each tile region requires a unique tile region id. This can be any alphanumeric string. To create a new tile region, provide a new tile region id.

To **update an existing tile region**, use the tile region id of the existing region. When you call `loadTileRegion`, expired resources will be updated and any missing resources will be loaded to the existing offline region. When updating a tile region, if you need to alter the `geometry` or `descriptors` you can do so in the `TileRegionLoadOptions`, but you can also provide a default object, which will reuse the existing `geometry` and `descriptors`. A failed load request can be reattempted with another `loadTileRegion()` call.

If there is already a pending loading operation for the tile region with the given id the pending loading operation will fail with an error of `Canceled` type.

**Java**

```java

OfflineManager offlineManager = new OfflineManager();

TilesetDescriptor mapsTilesetDescriptor = offlineManager.createTilesetDescriptor(
    new TilesetDescriptorOptions.Builder()
        .styleURI(Style.OUTDOORS)
        .minZoom((byte) 0)
        .maxZoom((byte) 16)
        .build()
);

TilesetDescriptor navTilesetDescriptor = mapboxNavigation.getTilesetDescriptorFactory().getLatest();

List<TilesetDescriptor> tilesetDescriptors = new ArrayList<>();
tilesetDescriptors.add(mapsTilesetDescriptor);
tilesetDescriptors.add(navTilesetDescriptor);

TileRegionLoadOptions tileRegionLoadOptions = new TileRegionLoadOptions.Builder()
    .geometry(TOKYO)
    .descriptors(tilesetDescriptors)
    .build();

Cancelable tileRegionCancelable = tileStore.loadTileRegion(
    TILE_REGION_ID,
    tileRegionLoadOptions,
    (TileRegionLoadProgressCallback) progress -> { /* Handle the download progress */ },
    (TileRegionCallback) expected -> { /* Handle the download result */ }
);

```

**Kotlin**

```kt

val offlineManager = OfflineManager()

val mapsTilesetDescriptor = offlineManager.createTilesetDescriptor(
    TilesetDescriptorOptions.Builder()
        .styleURI(Style.OUTDOORS)
        .minZoom(0)
        .maxZoom(16)
        .build()
)

val navTilesetDescriptor = mapboxNavigation.tilesetDescriptorFactory.getLatest()

val tileRegionLoadOptions = TileRegionLoadOptions.Builder()
    .geometry(TOKYO)
    .descriptors(listOf(mapsTilesetDescriptor, navTilesetDescriptor))
    .build()

val tileRegionCancelable = tileStore.loadTileRegion(
    TILE_REGION_ID,
    tileRegionLoadOptions,
    { progress ->
        // Handle the download progress
    },
    { expected ->
        // Handle the download result
    },
)
```

### List tile regions

Call `TileStore#getAllTileRegions` to get a list of available tile regions. This will return either an object (`Expected`) that includes a list of available tile regions or an error.

> **Note**
> 
> The callbacks will be executed on a `TileStore`-controlled worker thread. It is the responsibility of the developer to dispatch them to a controlled thread.

**Java**

```java

tileStore.getAllTileRegions(expected -> {
    // Handle regions
});
```

**Kotlin**

```kt

tileStore.getAllTileRegions { expected ->
    // Handle regions
}
```

### Delete tile regions

You can delete a tile region with `TileStore#removeTileRegion`.

**Java**

```java

tileStore.removeTileRegion(TILE_REGION_ID);
```

**Kotlin**

```kt

tileStore.removeTileRegion(TILE_REGION_ID)
```

> **Note**
> 
> This may not delete the downloaded tile packs immediately. Instead, it will mark the tileset as not being a part of an offline tile region, and the tileset will be removed from the disk cache during its normal cleanup process.

### Observe tile regions state

You can add `TileStoreObserver` to be notified when the state of any tile region changes.

**Java**

```java


TileStoreObserver tileStoreObserver = new TileStoreObserver() {
    @Override
    public void onRegionLoadProgress(@NonNull String id, @NonNull TileRegionLoadProgress progress) {
        // Called whenever the load progress of a TileRegion changes.
    }
    @Override
    public void onRegionLoadFinished(@NonNull String id, @NonNull Expected<TileRegionError, TileRegion> region) {
        // Called once a TileRegion load completes successfully, or is aborted due to cancellation or errors.
    }
    @Override
    public void onRegionRemoved(@NonNull String id) {
        // Called when a TileRegion was removed
    }
    @Override
    public void onRegionGeometryChanged(@NonNull String id, @NonNull Geometry geometry) {
        // Called when the geometry of a TileRegion was modified.
    }
    @Override
    public void onRegionMetadataChanged(@NonNull String id, @NonNull Value value) {
        // Called when the user-provided metadata associated with a TileRegion was changed.
    }
};
tileStore.addObserver(tileStoreObserver);

// remove observer when you don't need it
tileStore.removeObserver(tileStoreObserver);

```

**Kotlin**

```kt

val tileStoreObserver = object : TileStoreObserver() {
    override fun onRegionLoadProgress(id: String, progress: TileRegionLoadProgress) {
        // Called whenever the load progress of a TileRegion changes.
    }

    override fun onRegionLoadFinished(id: String, region: Expected<TileRegionError, TileRegion>) {
        // Called once a TileRegion load completes successfully, or is aborted due to cancellation or errors.
    }

    override fun onRegionRemoved(id: String) {
        // Called when a TileRegion was removed
    }

    override fun onRegionGeometryChanged(id: String, geometry: Geometry) {
        // Called when the geometry of a TileRegion was modified.
    }

    override fun onRegionMetadataChanged(id: String, value: Value) {
        // Called when the user-provided metadata associated with a TileRegion was changed.
    }
})
tileStore.addObserver(tileStoreObserver)

// remove observer when you don't need it
tileStore.removeObserver(tileStoreObserver)
```

## Tileset Version Management

The [`TilesetVersionManager`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-version-manager/) provides functionality to check for available tileset versions and determine if downloaded tilesets need updates based on version comparison and age thresholds. This is essential for keeping your offline navigation data up-to-date.

### Accessing `TilesetVersionManager`

The `TilesetVersionManager` is available through the [`MapboxNavigation`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core/-mapbox-navigation/tileset-version-manager.html) instance:

**Java**

```java

TilesetVersionManager tilesetVersionManager = mapboxNavigation.getTilesetVersionManager();
```

**Kotlin**

```kt

val tilesetVersionManager = mapboxNavigation.tilesetVersionManager
```

### Checking available versions

You can retrieve the list of available tileset versions from the server:

**Java**

```java

tilesetVersionManager.getAvailableVersions(new TilesetVersionManager.TilesetVersionsCallback() {
    @Override
    public void onVersionsResult(@NonNull Expected<Throwable, List<TilesetVersion>> versions) {
        if (versions.isValue()) {
            List<TilesetVersion> availableVersions = versions.getValue();
            // Handle available versions
        } else {
            Throwable error = versions.getError();
            // Handle error
        }
    }
});
```

**Kotlin**

```kt

tilesetVersionManager.getAvailableVersions { versions ->
    versions.onValue { availableVersions ->
        // Handle available versions
    }.onError { error ->
        // Handle error
    }
}
```

> **Note**
> 
> The callbacks will be executed on a worker thread. It is the responsibility of the developer to dispatch them to a controlled thread.

### Checking for updates

The `TilesetVersionManager` provides two main methods for checking if updates are available:

#### Check updates for all regions

Use [`TilesetVersionManager.getAvailableUpdates()`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-version-manager/get-available-updates.html) to check for updates across all downloaded regions:

**Java**

```java

// Check all regions with default age threshold (0 minutes)
tilesetVersionManager.getAvailableUpdates(new TilesetVersionManager.AllTilesetsUpdatesCallback() {
    @Override
    public void onUpdatesResult(@NonNull Expected<Throwable, List<TilesetUpdateAvailabilityResult.Available>> result) {
        if (result.isValue()) {
            List<TilesetUpdateAvailabilityResult.Available> updates = result.getValue();
            // Handle available updates
        } else {
            Throwable error = result.getError();
            // Handle error
        }
    }
});

// Check all regions with custom age threshold (60 minutes)
tilesetVersionManager.getAvailableUpdates(60, new TilesetVersionManager.AllTilesetsUpdatesCallback() {
    @Override
    public void onUpdatesResult(@NonNull Expected<Throwable, List<TilesetUpdateAvailabilityResult.Available>> result) {
        // Handle result
    }
});
```

**Kotlin**

```kt

// Check all regions with default age threshold (0 minutes)
tilesetVersionManager.getAvailableUpdates { result ->
    result.onValue { updates ->
        // Handle available updates
    }.onError { error ->
        // Handle error
    }
}

// Check all regions with custom age threshold (60 minutes)
tilesetVersionManager.getAvailableUpdates(maxAllowedAgeDifferenceMinutes = 60) { result ->
    result.onValue { updates ->
        // Handle available updates
    }.onError { error ->
        // Handle error
    }
}
```

#### Check updates for a specific region

Use [`TilesetVersionManager.getAvailableUpdate(regionId)`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-version-manager/get-available-update.html) to check for updates for a specific region:

**Java**

```java

String regionId = "my-region";

// Check specific region with default age threshold
tilesetVersionManager.getAvailableUpdate(regionId, new TilesetVersionManager.TilesetUpdatesCallback() {
    @Override
    public void onUpdatesResult(@NonNull Expected<Throwable, TilesetUpdateAvailabilityResult> result) {
        if (result.isValue()) {
            TilesetUpdateAvailabilityResult updateResult = result.getValue();
            if (updateResult instanceof TilesetUpdateAvailabilityResult.Available) {
                TilesetUpdateAvailabilityResult.Available available =
                    (TilesetUpdateAvailabilityResult.Available) updateResult;
                // Handle available update
            } else if (updateResult instanceof TilesetUpdateAvailabilityResult.NoUpdates) {
                // No updates needed
            }
        } else {
            Throwable error = result.getError();
            // Handle error
        }
    }
});

// Check specific region with custom age threshold
tilesetVersionManager.getAvailableUpdate(regionId, 60, new TilesetUpdatesCallback() {
    @Override
    public void onUpdatesResult(Expected<Throwable, TilesetUpdateAvailabilityResult> result) {
        // Handle result
    }
});
```

**Kotlin**

```kt

val regionId = "my-region"

// Check specific region with default age threshold
tilesetVersionManager.getAvailableUpdate(regionId) { result ->
    result.onValue { updateResult ->
        when (updateResult) {
            is TilesetUpdateAvailabilityResult.Available -> {
                // Handle available update
                val isAsap = updateResult.isAsap
                val currentVersion = updateResult.currentVersion
                val latestVersion = updateResult.latestVersion
            }
            is TilesetUpdateAvailabilityResult.NoUpdates -> {
                // No updates needed
            }
        }
    }.onError { error ->
        // Handle error
    }
}

// Check specific region with custom age threshold
tilesetVersionManager.getAvailableUpdate(regionId, 60) { result ->
    result.onValue { updateResult ->
        // Handle result
    }.onError { error ->
        // Handle error
    }
}
```

### Understanding update results

The [`TilesetUpdateAvailabilityResult`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/) provides information about update availability:

-   [`TilesetUpdateAvailabilityResult.Available`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/-available/) indicates that an update is available and provides information about update availability:
    -   [`regionId`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/-available/region-id.html): The ID of the region that needs updating
    -   [`currentVersion`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/-available/current-version.html): The downloaded version
    -   [`latestVersion`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/-available/latest-version.html): The latest available version
    -   [`isAsap`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/-available/is-asap.html): Whether the tiles should be updated as soon as possible (e.g., for blocked versions)
-   [`TilesetUpdateAvailabilityResult.NoUpdates`](https://docs.mapbox.com/android/navigation/api/coreframework/3.28.2/navigation/com.mapbox.navigation.core.navigator.offline/-tileset-update-availability-result/-no-updates/): Indicates that no updates are needed

### Age threshold configuration

The age threshold parameter (`maxAllowedAgeDifferenceMinutes`) determines when an update is recommended:

-   **0 minutes (default value)**: Any version difference will trigger an update recommendation
-   **Positive values**: Updates are only recommended if the current version is older than the specified threshold. For example, you can check for updates every 12 hours with `TimeUnit.HOURS.toMinutes(12)` or every 2 weeks with `TimeUnit.DAYS.toMinutes(14)`

This allows you to balance between keeping data fresh and avoiding unnecessary updates.

### Handling available updates

When the `TilesetVersionManager` indicates that updates are available, you need to do two main steps to apply the new tileset version:

#### 1. Update offline data

First, you need to update your offline data to the required version. Use the same process as described in the [Download a tile region](#download-a-tile-region) section, but with updated tileset descriptors that include the new version.

**Java**

```java

// Get the new tileset descriptor with the updated version
TilesetDescriptor navTilesetDescriptor = mapboxNavigation.getTilesetDescriptorFactory()
    .build(tilesDataset, tilesProfile, newTilesVersion, includeAdas);

// Update tile regions with the new tileset descriptor
```

**Kotlin**

```kt

// Get the new tileset descriptor with the updated version
val navTilesetDescriptor = mapboxNavigation.tilesetDescriptorFactory
    .build(
        tilesVersion = newTilesVersion,
        includeAdas = includeAdas,
    )

// Update tile regions with the new tileset descriptor
```

#### 2. Recreate `MapboxNavigation` instance

After the offline data has been successfully updated, you need to [recreate the `MapboxNavigation` instance](https://docs.mapbox.com/android/navigation/guides/initialization/) with the new tileset version:

**Java**

```java

// Destroy the current MapboxNavigation instance
// MapboxNavigationProvider.destroy();
// or
// MapboxNavigationApp.disable();

// Create new NavigationOptions with updated tileset version
NavigationOptions newNavOptions = new NavigationOptions.Builder(context)
    .routingTilesOptions(
        new RoutingTilesOptions.Builder()
            .tilesVersion(newTilesVersion)
            // other options
            .build()
    )
    .build();

// Create new MapboxNavigation instance
// MapboxNavigation newMapboxNavigation = MapboxNavigationProvider.create(newNavOptions);
// or
// MapboxNavigationApp.setup(newNavOptions);
```

**Kotlin**

```kt

// Destroy the current MapboxNavigation instance
// MapboxNavigationProvider.destroy()
// or
// MapboxNavigationApp.disable()

val newNavOptions = NavigationOptions.Builder(context)
    .routingTilesOptions(
        RoutingTilesOptions.Builder()
            .tilesVersion(newTilesVersion)
            // other options
            .build()
    )
    .build()

// Create new MapboxNavigation instance
// val newMapboxNavigation = MapboxNavigationProvider.create(newNavOptions)
// or
// MapboxNavigationApp.setup(newNavOptions)
```