Loading the Region Catalog
This page explains how to load and refresh the route-network and map-tile region catalogs before users choose required offline regions. Use cached data first, synchronize catalogs when needed, and handle partial catalog results from each subsystem.
Cache and TTL
syncRegions() synchronizes the road-network and map catalogs in parallel and applies the same cache policy to both. The default TTL is 24 hours. Each catalog atomically replaces its own cache, and a failed refresh does not delete the last successful result.
| Mode | Network behavior | Recommended use |
|---|---|---|
AUTO | Skips the network when the cache is complete and within its TTL. It refreshes only when missing or expired | Screen entry and automatic background refresh |
FORCE | Always refreshes from the network and returns an error when no validated network is available | User-initiated pull to refresh |
fetchRegionLists() reads only the local road-network and map caches without making a network request. To avoid leaving the region screen in a loading state, read and display the cache first, then run AUTO and read the caches again after synchronization. Keep the initial loading state only for a first installation with no cached catalog.
Cache-first Screen Implementation
OfflineRegionCatalogSyncResult contains synchronization details for both route and map catalogs. map.networkSkipped is true when AUTO uses a valid cached map catalog. A successful sync does not guarantee that downloadable regions exist. To verify, call fetchRegionLists() after synchronization to read the catalogs.
Country Filtering and Partial Results
The no-argument fetchRegionLists() overload queries United States by default. NBNavigation does not currently expose a public country-enumeration API. Obtain the supported full English country name from the deployment configuration, your product backend, or NextBillion.ai, then pass that exact value to fetchRegionLists(country, callback). Do not pass an ISO code, a localized name, or a whitespace-only string. Treat the country as product configuration rather than deriving it from the device locale.
OfflineRegionListResult may contain data from only the road-network or map side. Check routeError, mapError, hasRouteData, hasMapData, and regionRows together. Do not interpret an empty list after filtering on hasRoute and hasMap as proof that no data exists, because the screen can display whichever cache remains available.
Reading installed map regions on a cold start may access the disk. Use the asynchronous listInstalledMapTileRegions() API instead of reading Maps SDK storage directly on the main thread.
Region List Fields, Data Size, and Update Detection
After fetchRegionLists() succeeds, use result.regionRows as the primary screen model. It aligns route and map catalogs by regionId and preserves regions available from only one source. Filter on hasRoute && hasMap only when the product explicitly requires a complete offline-navigation package.
Result object OfflineRegionListResult
| Field | Meaning | Recommended use |
|---|---|---|
routeRegionList | Locally cached route catalog; null when unavailable or unreadable | Use for catalog metadata or grouped route queries |
mapRegionList | Locally cached map catalog; null when unavailable or unreadable | Use for catalog metadata or map diagnostics |
routeError / mapError | Source-specific error or stale-cache warning | The other source and regionRows may still be usable |
regionRows | Route and map entries aligned by regionId | Preferred source for a regional-list UI |
updatedAtMs | Wall-clock time when this combined result was constructed | This is not the last catalog-sync time |
hasRouteData | Whether routeRegionList exists | Does not mean every row contains route data |
hasMapData | Whether mapRegionList exists | Does not mean every row contains map data |
Read routeRegionList.listSyncedAtMs and mapRegionList.listSyncedAtMs for catalog freshness; updatedAtMs only timestamps this response. mapRegionList.listSyncStatus can be empty, ok, or failed. Do not infer synchronization success from total or an empty list alone without simultaneously inspecting routeError and mapError.
List item OfflineRegionListRow
| Field | Meaning | Recommended use |
|---|---|---|
regionId | Stable ID shared by the route and map catalogs | Use for download, pause, resume, cancel, delete, and version association |
routeRegion | OfflineRegionLeaf for this ID. It will be “null” when absent from the route catalog | Read route version, download state, progress, and bounds |
mapRegion | MapTileRegionListItem for this ID. It will be “null” when absent from the map catalog | Read map version, estimated size, and tile count |
displayName | Route adminL3, then map name, then Region #id | Suitable as the default UI title |
country | Route country, then map adminL0 | Can be “null”. Do not query with a localized replacement |
adminL1 | Route adminL1, then map adminL1 | May be “null” |
adminL2 | Route-catalog level-2 administrative name | The map catalog does not currently supply it. Can be “null” |
adminL3 | Route adminL3, then map adminL3 | Can be “null” |
routeSizeBytes | Estimated compressed route download size in bytes | “null” means the route side is absent but it does not mean zero size. |
mapSizeBytes | Estimated compressed map download size in bytes | “null” means the map side is absent but it does not mean zero size. |
hasRoute | routeRegion != null | Whether the row can provide a route package |
hasMap | mapRegion != null | Whether the row can provide a map package |
Route item routeRegion and OfflineRegionLeaf
| Field | Meaning | Recommended use |
|---|---|---|
regionId | Route-region ID | Should equal the outer row.regionId |
country / adminL1 / adminL2 / adminL3 | Catalog administrative hierarchy | adminL3 is normally displayed; values can be empty strings |
version | Current server route-catalog version | Normally consumed by the SDK updateAvailable calculation |
timestampSec | Catalog-version time in Unix epoch seconds | Used for version comparison; dataVersionLabel is available for display |
totalSizeBytes | Estimated compressed route-package size | Use for pre-download display and storage estimates |
downloadStatus | Can be one of IDLE, DOWNLOADING, COMPLETE, PARTIAL, FAILED, PAUSED, or UNKNOWN | Prefer isDownloaded, isPartial, or unified progress for business decisions |
tilesTotal / tilesDone | Planned and completed route-tile counts | Calculate detailed progress only when the total is valid |
detailSyncStatus | Raw region-detail or manifest synchronization state | Use for diagnostics, not as the only readiness gate |
catalogRemoved | The local entry is absent from the latest server catalog | Local data remains, so do not treat it as an update |
catalogUpdateAvailable | SDK-computed route-catalog update flag | Prefer the equivalent updateAvailable property |
boundaryBbox | WGS84 bounds derived from cached boundary GeoJSON | Use for viewport intersection when detail is present |
catalogBbox | WGS84 bounds supplied directly by the catalog | Use for coarse filtering before boundary detail is downloaded |
displayName | Derived from adminL3, adminL2, or regionId | The outer row.displayName also considers the map name |
| sizeWithUnit` | Human-readable totalSizeBytes | Useful when displaying only the route-package size |
isDownloaded / `isPartial | Derived from status and tilesDone/ tilesTotal | Use for route-side availability and resume controls |
updateAvailable | Public alias of catalogUpdateAvailable | After catalog sync, use it to show a route-update prompt |
dataVersionLabel | timestampSec formatted as yyyy-MM-dd | Display only. Do not parse it back for version comparison |
Map item mapRegion and MapTileRegionListItem
| Field | Meaning | Recommended use |
|---|---|---|
regionId | Map-region ID | Should equal the outer row.regionId |
name | Map-region name from the server catalog | Used by row.displayName when the route name is absent |
adminL0 | English country or level-0 administrative name | Used when filtering the map catalog by country |
adminL1 | Level-1 administrative name | Can be used for grouped display |
adminL3 | Level-3 administrative name | Can be used for finer display. adminL2 is currently not supplied |
version | Server map-region version. It can be null | Compare with the installed regionVersion |
totalSizeBytes | Estimated compressed map-package size | Use for pre-download display and storage estimates |
tileCount | Server-provided estimated tile count | An estimate, not a package-count limit |
timestamp | Raw server timestamp. It can be null and is preserved without unit conversion | Do not assume it to be in seconds. Prefer version for map-update comparison |
Calculate download size and available storage
For a first download, add non-null routeSizeBytes and mapSizeBytes to obtain the combined estimated compressed download size. This excludes extraction, database pages, temporary files, and filesystem overhead, so it is not the final on-disk size.
For a resumed download, when downloaded and total are available from observeOfflineProgress(), sum max(total - downloaded, 0) for both subtasks or else fall back to the full catalog estimate.
Recommended preflight: available bytes >= remaining download bytes + max(20% of remaining bytes, 100 MB). NBNavigation does not currently expose one combined storage-preflight result for route and map downloads, so the application should still use StatFs on the volume that contains the actual data directory. Check each volume separately if route and map data use different volumes. Insufficient storage can still surface through progress or callbacks as FAILED, FAILED_STORAGE, or a structured error.