Slide 1

Slide 1 text

Copyright 2018 Studyplus, Inc. All Rights Reserved. MapView in RecyclerView つまずいた話 Yuzuru Nakashima / Studyplus Inc. 2019.03.18 @ Otemachi.apk #02

Slide 2

Slide 2 text

自己紹介 ✎ なかてぃる affinity_robots nacatl ✎ スタディプラスのAndroidエンジニア ✎ 趣味: Magic the Gathering

Slide 3

Slide 3 text

目次 ✎ GoogleMapAPI ✎ したかったこと ✎ うまくいったこと ✎ つまずいたこと

Slide 4

Slide 4 text

GoogleMapPlatformAPI MapFragment? MapView?

Slide 5

Slide 5 text

GoogleMapPlatformAPI GoogleMapを表示するViewとFragmentを提供 - FragmentはLifeCycleの管理が楽(Viewだと面倒) - useViewLifecycleInFragment(true) - SupportLibrary版のSupportMapFragmentがある - LiteModeで表示すると単にbitmap表示するだけで軽い - 開発チームはオーストラリア(余談)

Slide 6

Slide 6 text

したかったこと What is want to do?

Slide 7

Slide 7 text

したかったこと 大学のキャンパス一覧を RecyclerViewで実装したかった

Slide 8

Slide 8 text

したかったこと - 既存からのリファクタリング - 不要なカスタムビュー撤廃 - ButterKnife -> DataBinding - Java -> Kotlin (つい最近Javaを超えた!!) - なんか突っかかる(UIスレッドで色々してる?) - MapView -> MapFragmentにしてLifeCycle処理任せる

Slide 9

Slide 9 text

うまくいったこと Success

Slide 10

Slide 10 text

うまくいったこと - 突っかかりの解消 カメラ位置の移動のために、GeoCoderを使って住所文字列から Map用のAddress クラスを取得する必要がある ここが遅いのにアイテム表示ごとにやってたから突っかかる -> Progress回しつつ初めに全アイテム分取得しておく RecyclerItemは住所文字列ではなくAddressを持つ

Slide 11

Slide 11 text

うまくいったこと RecyclerViewのサイクルに合わせた表示処理 - onCreateViewHolderでgetMap - onBindingViewHolderでmoveCamera - onViewRecycledでclear 参考: https://github.com/googlemaps/android-samples/blob/master/ApiDemos/java/app/s rc/main/java/com/example/mapdemo/LiteListDemoActivity.java

Slide 12

Slide 12 text

うまくいったこと RecyclerViewのサイクルに合わせた表示処理 - onCreateViewHolderでgetMap override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MapItemViewHolder(parent.inflate(viewType)).also { holder -> if (holder.binding is ListItemMapBinding) { holder.binding.campusMap.onCreate(null) holder.binding.campusMap.getMapAsync { map -> MapsInitializer.initialize(holder.itemView.context.applicationContext) mapType = GoogleMap.MAP_TYPE_NORMAL } } }

Slide 13

Slide 13 text

うまくいったこと RecyclerViewのサイクルに合わせた表示処理 - onBindViewHolderでmoveCamera override fun onBindViewHolder(holder: MapViewHolder, position: Int) { val mapListItem = getItem(position) holder.binding?.let { binding -> (binding as? ListItemMapBinding)?.let { holder.moveCamera(mapListItem.campusAddress) }

Slide 14

Slide 14 text

うまくいったこと RecyclerViewのサイクルに合わせた表示処理 - onViewRecycledでclear recyclerView.setRecyclerListener { holder -> if (holder is MapViewHolder) { holder.releaseMap() } } fun releaseMap() { googleMap?.run { clear() mapType = GoogleMap.MAP_TYPE_NONE } }

Slide 15

Slide 15 text

つまずいたこと Missteps

Slide 16

Slide 16 text

最初の一個以外真っ白になった MAP つまずいたこと

Slide 17

Slide 17 text

つまずいたこと FragmentRecyclerViewと相性が悪いらしく、 結局MapViewにした… (公式サンプルでもViewだった…) 参考: https://stackoverflow.com/questions/50391459/supportmapfra gment-on-a-recyclerview

Slide 18

Slide 18 text

途中のアイテムが世界地図のままのことがある (視点位置が指定した場所に移動していない) つまずいたこと これ MAP MAP MAP

Slide 19

Slide 19 text

つまずいたこと RecyclerView内の表示準備不備が原因 - 表示にはMapクラスとAddressクラスが必要 - onCreateViewHolderでgetMapAsync - onBindViewHolderでitemの持つAddressにMapの カメラ位置を移動させたいが、まだ取得できてない onCreate ViewHolder onBind ViewHolder (Address取得) 視点移動 したいのに Mapがない! Map取得! 時間(t) getMapAsync

Slide 20

Slide 20 text

MapとAddress両方をHolderでメンバ保持し、 どちらかが取れたタイミングで 視点移動処理を試す つまづいたこと onCreate ViewHolder onBind ViewHolder (Address取得) getMap Async ItemのAddress 取得!可能なら 視点移動! Map取得! 可能なら 視点移動! 時間(t)

Slide 21

Slide 21 text

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ~~ holder.binding.campusMap.getMapAsync { map -> MapsInitializer.initialize(holder.itemView.context.applicationContext) holder.showMapIfAble(map) mapType = GoogleMap.MAP_TYPE_NORMAL } } } つまづいたこと

Slide 22

Slide 22 text

まとめ Result

Slide 23

Slide 23 text

- 公式サンプルはきちんと見よう - ViewのLifeCycleを気にしよう

Slide 24

Slide 24 text

https://info.studyplus.co.jp/recruit

Slide 25

Slide 25 text

ご静聴ありがとうございました