【问题标题】:RecyclerView within a ViewPager unpopulated despite Adapter containing data尽管适配器包含数据,但 ViewPager 中的 RecyclerView 未填充
【发布时间】:2018-09-09 03:08:26
【问题描述】:

我目前正在使用ViewPagerTabLayout 来处理几个类似的片段。 ViewPager 中托管的片段都有一个RecyclerView。当我滑动超过一页时,片段(我认为?)被破坏。当我向后滑动时,它会重新创建。

经过调试,我发现 Fragment 中的适配器不为空,并且填充了之前的数据。但是,一旦片段可见,它就不再显示任何条目。

这是一个关于正在发生的事情的视频。

这是 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()
        }
    }

}

这是托管 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)
        }
    }
}

我用于分页的适配器

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
}

我已尝试覆盖 onSaveInstanceState 并从包中读取信息。它似乎没有做任何事情。问题似乎实际上是 RecyclerView 显示?它充满了数据,这就是我难过的原因。

【问题讨论】:

  • 你有没有尝试使用Android架构的ViewModel。
  • 不,但我的下一个任务是在我弄清楚这一点后实施 MVVM。最终这并不能解决问题,因为我不想每次重新创建片段时都访问 API。
  • 您不会每次都使用 ViewModel 访问 API。 ViewModel 可以让您在配置更改后幸免于难。所以这可能会奏效.. IMO
  • 使用 LiveData 实现 ViewModel 并没有解决问题。

标签: android android-fragments android-recyclerview kotlin android-viewpager


【解决方案1】:

尝试将setOffscreenPageLimit 用于ViewPager 以保持包含片段如下:

viewPager.setOffscreenPageLimit(NavigationPageAdapter.NUM_PAGES)

【讨论】:

  • 这行得通,但我想知道这样做的后果是什么?这个应用程序将成为一个移动音乐播放器。每个选项卡中可能包含数以万计的项目。我想他们会在记忆中保持活力?
  • 如果您使用 RecyclerView 以片段的形式显示项目,则无需担心其中有很多项目。另外,由于 ViewPager 中的 Fragment 数量较少,使用 setOffscreenPageLimit 并没有显着的内存使用。
【解决方案2】:

我已经找到了问题所在。虽然setOffScreenPageLimit(NavigationAdapter.NUM_PAGES) 确实有效,但由于内存消耗问题,我谨慎使用它。

事实证明,使用lazy 存储对视图的引用是不好的做法。由于onCreateViewArtistListFragment 的生命周期中被多次调用,因此没有引用当前在屏幕上膨胀的相同视图。

删除所有 lazy 实例化视图并使用 Android 扩展直接访问它们解决了我的问题。

【讨论】:

    猜你喜欢
    • 2021-06-10
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    相关资源
    最近更新 更多