我在构建代码的一部分时遇到了一些问题,该代码编辑服务器发送的缩略图并将它们呈现为 Google GroundOverlay。
这个问题似乎源于 Kotlin Coroutines。首先,谷歌的文档说地面覆盖层必须在主线程上创建。在主线程之外运行它们的创建会导致致命错误。所以我一直确保在主线程上制作这些GroundOverlays。但是,当尝试在 Main 之外的线程上创建位图时,我似乎根本没有覆盖。
class BarreMapFragment : Fragment(),
GoogleMap.OnCameraIdleListener,
GoogleMap.OnCameraMoveCanceledListener,
GoogleMap.OnCameraMoveListener,
GoogleMap.OnCameraMoveStartedListener,
OnMapReadyCallback {
//Main handler for google map/item styling
googleMapHandler = GoogleMapHandler(gMap!!, activity!!.applicationContext, DefaultTheme, lifecycle.coroutineScope)
. . .
open class GoogleMapHandler(val gMap: GoogleMap,
val context: Context,
val mapThemeInstructions: MapThemeInstructions,
val coroutineScope: CoroutineScope
) {
fun updateActiveUserAvatarPosition(position: LatLng) {
if (mActiveUserAvatar == null) {
coroutineScope.launch {
mActiveUserAvatar = mapObjectFactory.factory(
MapObject(
latitude = position.latitude,
longitude = position.longitude,
objectId = "SELF_AVATAR",
objectType = MapObjectType.USER_AVATAR,
timestamp = System.currentTimeMillis(),
weight = 20.toFloat()
), getOverlayWidthByZoom(dpScreenWidth, gMap.cameraPosition.target, gMap.cameraPosition.zoom)) as RenderedUserAvatarItem
}
}
mActiveUserAvatar?.updatePosition(position)
}
suspend fun factory(mapObject: MapObject, diameter: Float) : RenderedMapItem {
overlayDiameter = diameter
val item = RenderedUserAvatarItem(
mapObject,
buildOverlay(mapObject)
)
return item
}
@MainThread
private suspend fun buildOverlay(mapObject: MapObject) : GroundOverlay {
Log.d("UserOverlay", "I was called.")
//Get the bitmap from the resources
//TODO: We can do more with this later... Like custom avatars
//val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.ic_user_avatar)
val bitmap = withContext(Dispatchers.Default) {
async {
val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
val bitmap : Bitmap = drawableToBitmap(d)!!
bitmap
}
}.await()
//val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
//val bitmap : Bitmap = drawableToBitmap(d)!!
Log.d(TAG, "bitmap = " + bitmap.toString())
//Make bitmap descriptor
val descriptor = BitmapDescriptorFactory.fromBitmap(bitmap)
val overlayOptions = GroundOverlayOptions().image(descriptor)
//Position and size of groundoverlay
overlayOptions.position(LatLng(mapObject.latitude, mapObject.latitude) , overlayDiameter)
//Add the overlay to the map, get a handle and save it to public Overlay list
val mOverlay = gMap.addGroundOverlay(overlayOptions)
//Store the moment information in the overlay tag
mOverlay.tag = mapObject.objectId
return mOverlay
}
从主线程调用挂起函数。现在,
val bitmap = withContext(Dispatchers.Unconfined) {
async {
val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
val bitmap : Bitmap = drawableToBitmap(d)!!
bitmap
}
}.await()
和上面注释掉的部分(不使用异步)
val d: Drawable = context.getDrawable(R.drawable.ic_user_avatar)!!
val bitmap : Bitmap = drawableToBitmap(d)!!
两者都会产生一个没有问题的 GroundOverlay。当我将 Dispatchers.Unconfined 更改为其他任何内容时,就会出现问题。甚至 Dispatchers.Main 也会导致 GroundOverlay 不显示在地图上。GroundOverlays 制作完成,我用日志语句检查了它们。他们的透明度是预期的,他们的知名度也是如此。问题似乎与位图有关。我怀疑我不理解 await() 的工作方式。我想它会暂停挂起功能,直到位图返回并准备好。
这是用于隔离错误的简化代码。我确实需要在 Dispatchers.Default 上完成此操作,因为每个缩略图的样式都会根据位置和一天中的时间进行调整。如果在主线程上完成,这部分处理在 UI 上会很困难。