Async load

This commit is contained in:
Alexander Nozik 2022-07-14 20:53:41 +03:00
parent bebd33f859
commit f92ccb4838
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
3 changed files with 26 additions and 11 deletions

View File

@ -1,6 +1,7 @@
package centre.sciprog.maps.compose package centre.sciprog.maps.compose
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import kotlinx.coroutines.Deferred
import kotlin.math.floor import kotlin.math.floor
data class TileId( data class TileId(
@ -15,7 +16,7 @@ data class MapTile(
) )
interface MapTileProvider { interface MapTileProvider {
suspend fun loadTile(id: TileId): MapTile fun loadTileAsync(id: TileId): Deferred<MapTile>
val tileSize: Int get() = DEFAULT_TILE_SIZE val tileSize: Int get() = DEFAULT_TILE_SIZE
@ -27,3 +28,5 @@ interface MapTileProvider {
const val DEFAULT_TILE_SIZE = 256 const val DEFAULT_TILE_SIZE = 256
} }
} }
suspend fun MapTileProvider.loadTile(id: TileId): MapTile = loadTileAsync(id).await()

View File

@ -17,6 +17,7 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.pointer.* import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import centre.sciprog.maps.* import centre.sciprog.maps.*
import kotlinx.coroutines.launch
import mu.KotlinLogging import mu.KotlinLogging
import org.jetbrains.skia.Font import org.jetbrains.skia.Font
import org.jetbrains.skia.Paint import org.jetbrains.skia.Paint
@ -149,8 +150,10 @@ actual fun MapView(
if (i in indexRange && j in indexRange) { if (i in indexRange && j in indexRange) {
val tileId = TileId(zoom, i, j) val tileId = TileId(zoom, i, j)
try { try {
val tile = mapTileProvider.loadTile(tileId) launch {
mapTiles.add(tile) val tile = mapTileProvider.loadTileAsync(tileId)
mapTiles.add(tile.await())
}
} catch (ex: Exception) { } catch (ex: Exception) {
logger.error(ex) { "Failed to load tile $tileId" } logger.error(ex) { "Failed to load tile $tileId" }
} }

View File

@ -5,7 +5,10 @@ import androidx.compose.ui.graphics.toComposeImageBitmap
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.statement.readBytes import io.ktor.client.statement.readBytes
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import mu.KotlinLogging import mu.KotlinLogging
import org.jetbrains.skia.Image import org.jetbrains.skia.Image
import java.net.URL import java.net.URL
@ -16,7 +19,11 @@ import kotlin.math.pow
/** /**
* A [MapTileProvider] based on Open Street Map API. With in-memory and file cache * A [MapTileProvider] based on Open Street Map API. With in-memory and file cache
*/ */
public class OpenStreetMapTileProvider(private val scope: CoroutineScope, private val client: HttpClient, private val cacheDirectory: Path): MapTileProvider { public class OpenStreetMapTileProvider(
private val scope: CoroutineScope,
private val client: HttpClient,
private val cacheDirectory: Path,
) : MapTileProvider {
private val cache = HashMap<TileId, Deferred<ImageBitmap>>() private val cache = HashMap<TileId, Deferred<ImageBitmap>>()
private fun TileId.osmUrl() = URL("https://tile.openstreetmap.org/${zoom}/${i}/${j}.png") private fun TileId.osmUrl() = URL("https://tile.openstreetmap.org/${zoom}/${i}/${j}.png")
@ -53,20 +60,22 @@ public class OpenStreetMapTileProvider(private val scope: CoroutineScope, privat
Image.makeFromEncoded(byteArray).toComposeImageBitmap() Image.makeFromEncoded(byteArray).toComposeImageBitmap()
} }
override suspend fun loadTile(id: TileId): MapTile { override fun loadTileAsync(id: TileId): Deferred<MapTile> {
val indexRange = indexRange(id.zoom) val indexRange = indexRange(id.zoom)
if(id.i !in indexRange || id.j !in indexRange){ if (id.i !in indexRange || id.j !in indexRange) {
error("Indices (${id.i}, ${id.j}) are not in index range $indexRange for zoom ${id.zoom}") error("Indices (${id.i}, ${id.j}) are not in index range $indexRange for zoom ${id.zoom}")
} }
val image = cache.getOrPut(id) { val image = cache.getOrPut(id) {
downloadImageAsync(id) downloadImageAsync(id)
}.await()
return MapTile(id, image)
} }
companion object{ return scope.async {
MapTile(id, image.await())
}
}
companion object {
private val logger = KotlinLogging.logger("OpenStreetMapCache") private val logger = KotlinLogging.logger("OpenStreetMapCache")
private fun indexRange(zoom: Int): IntRange = 0 until 2.0.pow(zoom).toInt() private fun indexRange(zoom: Int): IntRange = 0 until 2.0.pow(zoom).toInt()
} }