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
import androidx.compose.ui.graphics.ImageBitmap
import kotlinx.coroutines.Deferred
import kotlin.math.floor
data class TileId(
@ -15,7 +16,7 @@ data class MapTile(
)
interface MapTileProvider {
suspend fun loadTile(id: TileId): MapTile
fun loadTileAsync(id: TileId): Deferred<MapTile>
val tileSize: Int get() = DEFAULT_TILE_SIZE
@ -26,4 +27,6 @@ interface MapTileProvider {
companion object {
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.unit.*
import centre.sciprog.maps.*
import kotlinx.coroutines.launch
import mu.KotlinLogging
import org.jetbrains.skia.Font
import org.jetbrains.skia.Paint
@ -149,8 +150,10 @@ actual fun MapView(
if (i in indexRange && j in indexRange) {
val tileId = TileId(zoom, i, j)
try {
val tile = mapTileProvider.loadTile(tileId)
mapTiles.add(tile)
launch {
val tile = mapTileProvider.loadTileAsync(tileId)
mapTiles.add(tile.await())
}
} catch (ex: Exception) {
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.request.get
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 org.jetbrains.skia.Image
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
*/
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 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()
}
override suspend fun loadTile(id: TileId): MapTile {
override fun loadTileAsync(id: TileId): Deferred<MapTile> {
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}")
}
val image = cache.getOrPut(id) {
downloadImageAsync(id)
}.await()
}
return MapTile(id, image)
return scope.async {
MapTile(id, image.await())
}
}
companion object{
companion object {
private val logger = KotlinLogging.logger("OpenStreetMapCache")
private fun indexRange(zoom: Int): IntRange = 0 until 2.0.pow(zoom).toInt()
}