【问题标题】:How to update ViewPager2 every 5 seconds如何每 5 秒更新一次 ViewPager2
【发布时间】:2021-10-23 21:39:52
【问题描述】:

我需要不断更新 Viewpager2 中的数据 我这样做, 每五秒调用一次

adapter?.updateData(it)      

fun updateData(items: List<TestDataObject>) {
        list = items
        notifyDataSetChanged()
    }

问题是在 notifyDataSetChange 之后页面显示错误的文本 我认为问题出在 notifyDataSetChange 中,但我不知道如何解决。

主活动

    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.view.View
    import androidx.lifecycle.LiveData
    import androidx.lifecycle.MutableLiveData
    import androidx.lifecycle.lifecycleScope
    import by.lwo.viewpagertest.databinding.ActivityMainBinding
    import kotlinx.coroutines.delay
    import kotlinx.coroutines.launch
    
    class MainActivity : AppCompatActivity() {
    
        lateinit var binding: ActivityMainBinding
        private var adapter: ViewPagerAdapter? = null
        val testList: MutableList<TestDataObject> = emptyList<TestDataObject>().toMutableList()
    
        private val _testLiveData = MutableLiveData<Event<List<TestDataObject>>>()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            binding = ActivityMainBinding.inflate(layoutInflater)
            setContentView(binding.root)
            setDataToList()
            setAdapter()
            constantlyUpdateList()
    
            _testLiveData.observeEvent(this) {
                adapter?.updateData(it)
                constantlyUpdateList()
           }
    
        }
    
        private fun constantlyUpdateList() {
            lifecycleScope.launch {
                delay(5000)
                setDataToList()
                _testLiveData.value = Event(testList)
            }
        }
    
        private fun setDataToList() {
            testList.clear()
            repeat(6) {
                testList.add(
                    TestDataObject(
                        titleText = "title for page $it",
                        infoText = "infoText for page $it"
                    )
                )
            }
        }
    
        private fun setAdapter(){
            binding.apply {
                adapter = ViewPagerAdapter(testList)
                viewPager.adapter = adapter
                viewPager.offscreenPageLimit = testList.size
            }
        }
    }

适配器

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import by.lwo.viewpagertest.databinding.HolderTestBinding

class ViewPagerAdapter(var list: List<TestDataObject>) : RecyclerView.Adapter<ViewPagerAdapter.TestHolder>() {

    lateinit var binding: HolderTestBinding

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerAdapter.TestHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.holder_test, parent, false)
        binding = DataBindingUtil.bind(view)!!
        return TestHolder(view)
    }

    override fun onBindViewHolder(holder: ViewPagerAdapter.TestHolder, position: Int) {
        holder.bind(list[position])
    }

    override fun getItemCount(): Int = list.size

    fun updateData(items: List<TestDataObject>) {
        list = items
        notifyDataSetChanged()
    }

    inner class TestHolder(containerView: View) : RecyclerView.ViewHolder(containerView) {
        fun bind(testDataObject: TestDataObject) {
            binding.apply {
                titleTv.text = testDataObject.titleText
                textTv.text = testDataObject.infoText
            }
        }
    }

}

data class TestDataObject(val titleText: String = "", val infoText: String = "")

【问题讨论】:

    标签: android android-recyclerview kotlin-coroutines android-viewpager2


    【解决方案1】:

    我看到两个主要问题:

    1. notifyDataSetChanged 方法将强制您的适配器重新渲染您在活动中拥有的整个项目集。您的列表与新列表仅在一个元素上有所不同并不重要:它将全部重新渲染。
      我建议使用ListAdapter,它将为您处理设置submitList 方法。它针对您将经常更新列表的用例进行了优化。

    2. 最重要的是,您的适配器的构建方式。你有财产:

    lateinit var binding: HolderTestBinding

    在每个onCreateViewHolder 调用中都会设置。但是,它是一个类字段,每次设置时,旧持有者的引用都会丢失,并且在每个 TestHolder 实例中,您将引用最后一个膨胀的绑定,因此,您的所有视图持有者将引用完全相同的视图持有者,而不是他们自己的。
    更好的方法是将绑定传递给每个持有者的构造函数:

    class ViewPagerAdapter(...) : ListAdapter(...) {
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerAdapter.TestHolder {
            val view = LayoutInflater.from(parent.context)
                .inflate(R.layout.holder_test, parent, false)
            val holder = DataBindingUtil.bind(view)?.let {
                TestHolder(it)
            }
            return holder!!
        }
    
        // 'inner' modifier is not needed
        class TestHolder(private val binding: TestHolderBinding) : RecyclerView.ViewHolder(binding.root) {
            fun bind(testDataObject: TestDataObject) {
                // this 'binding' will reference their own binding, and not the 'global' one :)
                binding.apply {
                    titleTv.text = testDataObject.titleText
                    textTv.text = testDataObject.infoText
                }
            }
        }
    } 
    

    【讨论】:

    • 你能检查一下这个issue
    猜你喜欢
    • 1970-01-01
    • 2015-06-22
    • 1970-01-01
    • 2022-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    相关资源
    最近更新 更多