サーバーが送信したサムネイルを編集し、それらを Google GroundOverlay としてレンダリングするコードのセクションを構築する際に問題が発生しています。
この問題は、Kotlin コルーチンに起因しているようです。まず、Google のドキュメントによると、グラウンド オーバーレイはメイン スレッドで作成する必要があります。それらの作成をメイン スレッドから実行すると、致命的なエラーが発生します。したがって、これらの GroundOverlays をメイン スレッドで作成するようにしました。ただし、メインからスレッドにビットマップを作成しようとすると、オーバーレイがまったく表示されないようです。
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
}
suspend 関数は、メイン スレッドから呼び出されます。今、
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 での処理が難しくなります。