Офлайн-карты и хранилище¶
Оба менеджера висят на MapKit:
val storageManager = MapKit.getInstance().storageManager
val offlineCacheManager = MapKit.getInstance().offlineCacheManager
Хранилище¶
StorageManager сообщает и ограничивает то, что MapKit держит на диске: кеш тайлов и всё остальное,
что он скачивает. Все методы асинхронные и отвечают через колбэк.
storageManager.computeSize { bytes, error ->
when {
error != null -> showError(error)
bytes != null -> show("${bytes / 1024 / 1024} MB")
}
}
Колбэк получает одно из двух: размер или runtime.Error, объясняющую, почему размера нет.
storageManager.maxTileStorageSize { bytes, _ -> println("limit: $bytes") }
storageManager.setMaxTileStorageSize(200L * 1024 * 1024) { bytes, error ->
if (error == null) println("limit is now $bytes")
}
storageManager.resetMaxTileStorageSize { _, _ -> }
storageManager.clear { println("cache cleared") }
clear() необратим
Он сбрасывает кеш тайлов, и карта скачает всё заново при следующем показе.
Об ошибках, на которые MapKit наткнулся сам, вне ваших вызовов, сообщает слушатель:
private val storageErrorListener = StorageErrorListener { error ->
when (error) {
is DiskFullError -> askToFreeSpace()
is DiskWriteAccessError -> reportUnwritableStorage()
is DiskCorruptError -> offerToClearCache()
else -> report(error)
}
}
storageManager.addStorageErrorListener(storageErrorListener.asWeakRef())
Офлайн-карты¶
OfflineCacheManager скачивает регионы целиком, чтобы карта работала без сети.
Найти регион¶
val regions: List<Region> = offlineCacheManager.regions()
val moscow = regions.firstOrNull { it.name == "Москва" }
Region — value-тип:
data class Region(
val id: Int,
val name: String,
val country: String,
val center: Point,
val size: LocalizedValue,
val releaseTime: Instant,
val parentId: Int?,
)
size — это LocalizedValue: число плюс строка, которую MapKit уже отформатировал для текущей
локали, так что size.text — то, что показывают, а size.value — то, что сравнивают.
Список заполняется асинхронно; если вы показываете его при запуске, подпишитесь до чтения:
private val listUpdatesListener = RegionListUpdatesListener { show(offlineCacheManager.regions()) }
offlineCacheManager.addRegionListUpdatesListener(listUpdatesListener.asWeakRef())
Регионы, покрывающие точку, без перебора всего списка:
offlineCacheManager.requestRegionsAtPoint(point) { regionIds, error ->
if (error != null) report(error.description) else show(regionIds.orEmpty())
}
Колбэк получает идентификаторы регионов; сопоставить их с полными Region помогает regions().
Скачивание¶
class OfflineController(private val manager: OfflineCacheManager) {
private val regionListener = RegionListener(
onRegionStateChanged = { regionId -> show(regionId, manager.getState(regionId)) },
onRegionProgress = { regionId -> showProgress(regionId, manager.getProgress(regionId)) },
)
private val errorListener = ErrorListener(
onError = { report(it) },
onRegionError = { error, regionId -> report(regionId, error) },
)
init {
manager.addRegionListener(regionListener.asWeakRef())
manager.addErrorListener(errorListener.asWeakRef())
}
fun download(regionId: Int) {
if (manager.mayBeOutOfAvailableSpace(regionId)) {
warnAboutSpace()
return
}
manager.startDownload(regionId)
}
fun pause(regionId: Int) = manager.pauseDownload(regionId)
fun stop(regionId: Int) = manager.stopDownload(regionId)
fun delete(regionId: Int) = manager.drop(regionId)
}
getProgress(regionId) — это 0f..1f. getState(regionId) — одно из:
| Состояние | Что означает |
|---|---|
AVAILABLE |
можно скачать |
DOWNLOADING |
скачивается |
PAUSED |
приостановлено, продолжается через startDownload |
COMPLETED |
скачано и актуально |
OUTDATED |
скачано, но вышла новая версия |
NEED_UPDATE |
нужно обновить, прежде чем использовать |
UNSUPPORTED |
эта версия MapKit не умеет им пользоваться |
getDownloadedReleaseTime(regionId) возвращает дату выпуска скачанной копии или null, если её
нет. getCities(regionId) перечисляет города региона — то, что показывают под его названием.
stopDownload отменяет и выбрасывает скачанное; pauseDownload его сохраняет.
drop и clear удаляют данные
drop(regionId) удаляет один скачанный регион, clear { } — всё, что держит офлайн-кеш. Ни то,
ни другое не спрашивает подтверждения.
Сеть и обновления¶
offlineCacheManager.allowUseCellularNetwork(false)
offlineCacheManager.enableAutoUpdate(true)
Где лежит кеш¶
offlineCacheManager.requestPath { path -> println("cache is at $path") }
offlineCacheManager.computeCacheSize { size -> println("$size bytes") }
Перенос — например, на SD-карту — сообщает прогресс и может завершиться ошибкой:
private val dataMoveListener = DataMoveListener(
onDataMoveCompleted = { println("moved") },
onDataMoveError = { error -> report(error.description) },
onDataMoveProgress = { percent -> showProgress(percent) },
)
offlineCacheManager.moveData(newPath, dataMoveListener.asWeakRef())
setCachePath направляет MapKit в другую папку, ничего не перенося:
offlineCacheManager.setCachePath(newPath) { error ->
if (error != null) report(error.description)
}
isLegacyPath(regionId) сообщает, лежит ли регион ещё в раскладке, которой пользовалась более
старая версия MapKit.
OfflineCacheError¶
description — это String? с тем, что MapKit говорит о произошедшем; error — типизированная
причина runtime.Error?, когда она есть.
На iOS сравнивается по значению
OfflineCacheError оборачивает NSError на iOS, а NSError реализует isEqual: со значимой
семантикой. Две разные ошибки с одинаковыми domain, code и userInfo поэтому окажутся равны на
iOS и не равны на Android. Считайте равенство признаком «та же самая ошибка», а не «тот же
объект» — см. Идентичность хендлов.