Fix tile loading lock
This commit is contained in:
parent
9f6386a8c2
commit
f49ff34a18
@ -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 io.ktor.utils.io.CancellationException
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.jetbrains.skia.Font
|
import org.jetbrains.skia.Font
|
||||||
@ -185,8 +186,10 @@ actual fun MapView(
|
|||||||
try {
|
try {
|
||||||
mapTiles += deferred.await()
|
mapTiles += deferred.await()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
//displaying the error is maps responsibility
|
if (ex !is CancellationException) {
|
||||||
logger.error(ex) { "Failed to load tile with id=$id" }
|
//displaying the error is maps responsibility
|
||||||
|
logger.error(ex) { "Failed to load tile with id=$id" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ 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 io.ktor.utils.io.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -37,6 +38,7 @@ class OpenStreetMapTileProvider(
|
|||||||
* Download and cache the tile image
|
* Download and cache the tile image
|
||||||
*/
|
*/
|
||||||
private fun CoroutineScope.downloadImageAsync(id: TileId) = async(Dispatchers.IO) {
|
private fun CoroutineScope.downloadImageAsync(id: TileId) = async(Dispatchers.IO) {
|
||||||
|
|
||||||
id.cacheFilePath()?.let { path ->
|
id.cacheFilePath()?.let { path ->
|
||||||
if (path.exists()) {
|
if (path.exists()) {
|
||||||
try {
|
try {
|
||||||
@ -48,40 +50,46 @@ class OpenStreetMapTileProvider(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
//semaphore works only for actual download
|
||||||
//semaphore works only for actual download
|
semaphore.withPermit {
|
||||||
semaphore.withPermit {
|
val url = id.osmUrl()
|
||||||
val url = id.osmUrl()
|
val byteArray = client.get(url).readBytes()
|
||||||
val byteArray = client.get(url).readBytes()
|
|
||||||
|
|
||||||
logger.debug { "Finished downloading map tile with id $id from $url" }
|
logger.debug { "Finished downloading map tile with id $id from $url" }
|
||||||
|
|
||||||
id.cacheFilePath()?.let { path ->
|
id.cacheFilePath()?.let { path ->
|
||||||
logger.debug { "Caching map tile $id to $path" }
|
logger.debug { "Caching map tile $id to $path" }
|
||||||
|
|
||||||
path.parent.createDirectories()
|
path.parent.createDirectories()
|
||||||
path.writeBytes(byteArray)
|
path.writeBytes(byteArray)
|
||||||
}
|
|
||||||
|
|
||||||
Image.makeFromEncoded(byteArray).toComposeImageBitmap()
|
|
||||||
}
|
}
|
||||||
} catch (ex: Exception){
|
|
||||||
//if loading is failed for some reason, clear the cache
|
Image.makeFromEncoded(byteArray).toComposeImageBitmap()
|
||||||
cache.remove(id)
|
|
||||||
throw ex
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun CoroutineScope.loadTileAsync(
|
override fun CoroutineScope.loadTileAsync(
|
||||||
tileId: TileId,
|
tileId: TileId,
|
||||||
): Deferred<MapTile> {
|
): Deferred<MapTile> {
|
||||||
|
|
||||||
//start image download
|
//start image download
|
||||||
val image = cache.getOrPut(tileId) {
|
val imageDeferred = cache.getOrPut(tileId) {
|
||||||
downloadImageAsync(tileId)
|
downloadImageAsync(tileId)
|
||||||
}
|
}
|
||||||
|
|
||||||
//collect the result asynchronously
|
//collect the result asynchronously
|
||||||
return async { MapTile(tileId, image.await()) }
|
return async {
|
||||||
|
val image = try {
|
||||||
|
imageDeferred.await()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
cache.remove(tileId)
|
||||||
|
if(ex !is CancellationException) {
|
||||||
|
logger.error(ex) { "Failed to load tile image with id=$tileId" }
|
||||||
|
}
|
||||||
|
throw ex
|
||||||
|
}
|
||||||
|
MapTile(tileId, image)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user