maplibre / maplibre-native

MapLibre Native - Interactive vector tile maps for iOS, Android and other platforms.
https://maplibre.org
BSD 2-Clause "Simplified" License
925 stars 280 forks source link

Replace usage of `android.os.AsyncTask` with Kotlin Coroutines #2436

Open louwers opened 1 month ago

louwers commented 1 month ago

As mentioned by @westnordost in this comment AsyncTask is deprecated and we should replace our usage of it with more modern APIs like Kotlin Coroutines.

A developer could claim a bounty under the modernization bounty direction for this work.

westnordost commented 1 month ago

Five cents from a developer using Kotlin: Migrating to Kotlin coroutines is something that should not be done in isolation only to replace AsyncTasks but in concert with generally changing also the API (or at least internally) to use suspending functions rather than callback-based functions. I am not sure how suspending APIs translate to Java code on the surface, though. Maybe, from the point of view of Java code, suspending functions look like functions with a callback parameter?

With Kotlin's suspending functions, the API to initialize the map could look like this, instead of juggling with callbacks:

suspend fun initMap() {
  val map = mapView.getMap()
  val style = map.setStyle("mapstyle.json")
  style.addImage("someImg", getDrawable(R.drawable.someImg))
  // ...
}

These look like blocking calls, and that's the point, that you can write suspending code like normal code.

In fact, what I did was to write extension functions to wrap the calls for my use into a suspending API to profit of this convenience myself. E.g.


suspend fun MapView.awaitGetMap(): MapLibreMap = suspendCoroutine { cont ->
    getMapAsync { cont.resume(it) }
}

To make a blocking API that has no callback suspending, one would e.g.


suspend fun Style.awaitAddImage(name: String, bitmap: Bitmap) { 
    withContext(IO) { addImage(name, bitmap) }
}

Now, since the native part of MapLibre handles most of the asynchronousness, I guess internally it does make sense to stay with a callback-based approach. So, take my comment with a grain of salt, I reckon it is probably not that helpful / applicable.