他にもSingle Activity関連はありましたが、とりあえず大きなところでいうとこれが勉強になったので書いておきます。
セッションのリストに戻った時にスクロールの位置が戻る問題
結論から言うとFragmentのライフサイクルへの理解が足りませんでした。
起こった問題
セッションの詳細の画面から、セッションのリストに戻った時にスクロールの位置が戻る問題がありました。
https://github.com/DroidKaigi/conference-app-2019/issues/33
問題があった当時のコードはこれです。savedInstanceState
がないときにcommitしています。これの何が問題なのでしょうか?

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupBottomSheet(savedInstanceState)
private fun setupBottomSheet(savedInstanceState: Bundle?) {
if (savedInstanceState == null) { // savedInstanceStateがないときだけcommit
val fragment: Fragment = when (val tab = SessionPage.pages[args.tabIndex]) {
...
SessionPage.Favorite -> {
BottomSheetFavoriteSessionsFragment.newInstance()
}
}
childFragmentManager
.beginTransaction()
.replace(R.id.sessions_sheet, fragment)
.disallowAddToBackStack()
.commit()
}
原因ととりあえずの解決策
なぜかというとFragmentがバックスタックから戻ってきたときはsavedInstanceState
がnullになるため、replaceしてしまうためです。
**childFragmentManager.findFragmentByTag(tab.title)**によりFragmentManager判定します
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupBottomSheet(savedInstanceState)
private fun setupBottomSheet(savedInstanceState: Bundle?) {
// suppress fragment replacement
val tab = SessionPage.pages[args.tabIndex]
if (savedInstanceState == null &&
childFragmentManager.findFragmentByTag(tab.title) == null
) {
最終的な解決策
ここで自分がうまく動いた!とツイートします
そこで以下のツッコミが入ります
このPRはsetupBottomSheetをonCreateで呼ぶだけで修正できるのではないかと思いました。
— くぼぼ (@swiz_ard) 2019年1月9日
ここで以下のことを学びました。
バックスタックから戻ってきたときはonCreateは呼ばれずonCreateViewやonActivityCreatedは呼ばれる。
孫フラグメントを作るときはFragmentのonCreateでcommit()をすることで、フラグメントが無駄にまた作られることを防げる。
https://github.com/xxv/android-lifecycle より
最終的に以下のようにonCreateで実装すれば完成です!
https://github.com/DroidKaigi/conference-app-2019/blob/e714989139f182fe499b1b3d4d4a4f5e8b9cd9cc/feature/session/src/main/java/io/github/droidkaigi/confsched2019/session/ui/SessionPageFragment.kt#L91
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
setupSessionsFragment()
}
}
...
private fun setupSessionsFragment() {
val tab = SessionPage.pages[args.tabIndex]
val fragment: Fragment = when (tab) {
...
SessionPage.Favorite -> {
BottomSheetFavoriteSessionsFragment.newInstance()
}
}
childFragmentManager
.beginTransaction()
.replace(R.id.sessions_sheet, fragment, tab.title)
.disallowAddToBackStack()
.commit()
}