Reputation: 699
I'm currently using a ViewPager
and TabLayout
for a couple of similar fragments. The fragments hosted within the ViewPager all have a RecyclerView
. When I swipe more than one page over, the Fragment (I think?) is destroyed. When I swipe back it's recreated.
Upon debugging, I found that the adapter within the Fragment is non null and populated with the data from before. However, once the fragment is visible it no longer displays any entries.
Here's a video of what's going on.
This is a fragment within the ViewPager
class ArtistListFragment : Fragment(), ListView {
override val title: String
get() = "Artists"
private val artistList: RecyclerView by lazy { artist_list }
@Inject lateinit var api: SaddleAPIManager
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
= container?.inflate(R.layout.fragment_list_artist)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
artistList.apply {
setHasFixedSize(true)
if (adapter == null) {
adapter = ViewTypeAdapter(mapOf(AdapterConstants.ARTIST to ArtistDelegateAdapter()))
}
layoutManager = LinearLayoutManager(context)
if (savedInstanceState != null && savedInstanceState.containsKey("artist")) {
(adapter as ViewTypeAdapter).setItems(savedInstanceState.getParcelableArrayList<Artist>("artists"))
}
}
(activity?.application as SaddleApplication).apiComponent.inject(this)
refreshData()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelableArrayList(
"artists",
(artistList.adapter as ViewTypeAdapter).items as ArrayList<out Parcelable>
)
}
private fun refreshData() = launch(UI) {
val result = withContext(CommonPool) { api.getArtists() }
when(result) {
is Success -> (artistList.adapter as ViewTypeAdapter).setItems(result.data.results)
is Failure -> Snackbar.make(artistList, result.error.message ?: "Error", Snackbar.LENGTH_LONG).show()
}
}
}
This is the Fragment hosting the ViewPager
class NavigationFragment : Fragment() {
private val viewPager: ViewPager by lazy { pager }
private val tabLayout: TabLayout by lazy { tab_layout }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
= container?.inflate(R.layout.fragment_navigation)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewPager.apply {
adapter = NavigationPageAdapter(childFragmentManager)
}
tabLayout.apply {
setupWithViewPager(viewPager)
}
}
}
The adapter I'm using for paging
class NavigationPageAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
companion object {
const val NUM_PAGES = 4
}
private val pages: List<Fragment> = (0 until NUM_PAGES).map {
when (it) {
0 -> ArtistListFragment()
1 -> AlbumListFragment()
2 -> TrackListFragment()
else -> PlaylistListFragment()
} as Fragment
}
override fun getItem(position: Int): Fragment = pages[position]
override fun getCount(): Int = NUM_PAGES
override fun getPageTitle(position: Int): CharSequence? = (pages[position] as ListView).title
}
I've tried overriding onSaveInstanceState
and reading the information from the bundle. It doesn't seem to do anything. The problem seems to actually be the RecyclerView displaying? It's populated with data which is why I'm stumped.
Upvotes: 0
Views: 573
Reputation: 699
I've figured out the problem. While setOffScreenPageLimit(NavigationAdapter.NUM_PAGES)
did work, I am cautious to use it because of memory consumption concerns.
As it turns out, storing references to views using lazy
is bad practice. Since onCreateView
gets called many times in the lifecycle of the ArtistListFragment
the same view wasn't being referenced that was currently inflated on the screen.
Removing all lazy
instantiated views and accessing them directly with the Android Extensions solved my problem.
Upvotes: 0
Reputation: 22832
Try to use setOffscreenPageLimit
for ViewPager
to keep containing fragments as below:
viewPager.setOffscreenPageLimit(NavigationPageAdapter.NUM_PAGES)
Upvotes: 1