简体   繁体   English

如何每 5 秒更新一次 ViewPager2

[英]How to update ViewPager2 every 5 seconds

I need to keep updating data in Viewpager2 i do it like this, call every five seconds我需要不断更新 Viewpager2 中的数据我是这样做的,每五秒调用一次

adapter?.updateData(it)      

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

the problem is that the pages display the wrong text after notifyDataSetChange I think the problem is in notifyDataSetChange, but I don't know how to fix it.问题是页面在notifyDataSetChange 后显示错误的文本我认为问题出在notifyDataSetChange 中,但我不知道如何解决。

MainActivity主要活动

    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
            }
        }
    }

Adapter适配器

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 = "")

I see two main problems:我看到两个主要问题:

  1. The notifyDataSetChanged method will force you adapter to re-render the whole set of items you have on your activity. notifyDataSetChanged方法将强制您的适配器重新呈现您在活动中拥有的整套项目。 It doesn't matter that your list differs from the new one in just one element: it'll get re-rendered in its totality.您的列表与新列表仅在一个元素上有所不同并不重要:它将整体重新呈现。
    I'd recommend to use ListAdapter , which will handle you set for you with the submitList method.我建议使用ListAdapter ,它将使用submitList方法为您处理设置。 It is optimized for the use cases where you'll be updating your list very often.它针对您经常更新列表的用例进行了优化。

  2. And most importantly, the way your adapter is built.最重要的是,适配器的构建方式。 You have the property:您拥有以下财产:

lateinit var binding: HolderTestBinding

Which is being set in every onCreateViewHolder call.这是在每个onCreateViewHolder调用中设置的。 However, it is a class field, and every time it is set, the reference of the older holder will be lost and, in every TestHolder instance, you'll be referencing the last inflated binding, hence, all of your view holders will be referencing the exact same view holder, instead of their own.但是,它是一个类字段,每次设置时,旧持有者的引用都会丢失,并且在每个TestHolder实例中,您将引用最后一个膨胀的绑定,因此,您的所有视图持有者都将是引用完全相同的视图持有者,而不是他们自己的。
A better way of doing this is passing the binding to the constructor of every holder:一个更好的方法是将绑定传递给每个持有者的构造函数:

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
            }
        }
    }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM