Posted at

【Kotlin】FragmentでViewPagerを使う時の注意点(再読み込みできない)

BottomNavigationViewのタブで切り替え表示をするFragmentのうちの1つで

ViewPagerを使って実装をしていて


BottomNavigationViewのタブを切り替えると実行されるはずの読み込み処理が実行されず、かつ直前に読み込んでいたデータも表示されなくなった

という現象が起きて嵌りました。

【画面構成(階層)】

MainActivity(BottomNavigationViewを使用)

  |- ParentFragment(ViewPagerを使用)

    |- ViewPager

      |- ChildFragments(ViewPagerの各ページに表示するFragment達)

先に解決策の載せておきます。↓↓


解決策

ViewPagerにセットするFragmentPagerAdapterのインスタンスを生成する時に


childFragmentManager

を渡す。これで解決しました。


FragmentPagerAdapter(解決後)


val adapter = FragmentPagerAdapter(childFragmentManager) //← ここ
viewPager.adapter = adapter

class AroundPagerAdapter(fragmentManager: FragmentManager?) :
FragmentPagerAdapter(fragmentManager) {

// 省略
}



FragmentPagerAdapter(解決前)


val adapter = FragmentPagerAdapter(fragmentManager)
viewPager.adapter = adapter

class AroundPagerAdapter(fragmentManager: FragmentManager?) :
FragmentPagerAdapter(fragmentManager) {

// 省略
}



実際に起きていたこと

BottomNavigationViewのタブから別タブに切り替えて再びそのタブに戻ってきたとき、

FragmentPagerAdapter#getItem() 

が呼ばれず、 ViewPager 内が再読込みされない現象が起きていました。

なぜ起きたのか、、、

①FragmentPagerAdapterはメモリ上にViewPagerの子Fragment(ChildFragments)を全て保持する

 → タブを切り替えた時は以前のものが再利用される

 FragmentPagerAdapter

②BottomNavigationViewのタブ切り替えだとParentActivityは生きたまま

 → FragmentManagerはViewPager内の子Fragment達(ChildFragments)を保持したままになり、 FragmentPagerAdapter#getItem() が呼ばれない

①②に対して、childFragmentManagerを使うと


保持される ViewPager 内のChildFragmentsはParentFragmentのFragmentManagerで管理される。


→タブを切り替えたときにはParentFragmentのインスタンスを再生成するのでそのタイミングでFragmentManagerがリセットされる


→新しくChildFragmentsのインスタンスを生成するので「FragmentPagerAdapter#getItem()」 が呼ばれて再読込みが始まるようになる。

(余談)

ViewPager のスワイプが起きたときは ParentFragment が生きている限り、 FragmentManager 内で ChildFragments が管理されるので、通常通り効率的にスワイプできるようになる。


まとめ

かなり嵌りましたが、解決してみるとあっけなかったですね 笑

以上です。