MapView と ViewPager2 の組み合わせでハマる

新しめの端末では問題ないのですが API25(Android 7) あたりから問題がありました。

発生するエラー

MapView と ViewPager2 を一つの画面に配置して、画面の状態を復元するような操作をすると、こんなログを出してクラッシュします。
java.lang.IllegalArgumentException: Wrong state class, expecting View State but received class androidx.recyclerview.widget.RecyclerView$SavedState instead. This usually happens when two views of different type have the same id in the same hierarchy. This view's id is id/0x1. Make sure other views do not use the same id.
内容としては、違う View なのに同じ View ID (0x1) が割り当てられてるから復元できないよ、という感じです。

原因

イシューが登録されていました。 MapView や ViewPager2 の中に明示的に ID が指定されていない View があり、実行時に ID が割り当てられるのですが、それが並行して動作することで同じ ID を割り当ててしまうようです。 なので、回避策として ID の採番をこちら側で進めてしまうといいらしいです。 詳細は、上記リンク先を参照ください。

具体的な回避コード(私の場合)

onCreateView() の中で、View を inflate する前に ID の採番を進めました。
override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    for (i in 0 until 10) ViewCompat.generateViewId()
    binding = FragmentMainBinding.inflate(inflater, container, false)
    binding.mapView.onCreate(savedInstanceState)
    binding.mapView.getMapAsync(this)
    return binding.root
}
ちなみに、今回調査を進めるにあたり、初めて Layout Inspector を使いました。 Android Studio の「Tools」→「Layout Inspector」で呼び出せるやつです。 Layout Inspector のツールバーで「Expand All」を実行すると、ビュー階層の中で同じ ID が割り当てられている View がすぐにわかりました。

コメントを残す

メールアドレスが公開されることはありません。