MVVM中RecyclerView中的分页重复值
Posted
技术标签:
【中文标题】MVVM中RecyclerView中的分页重复值【英文标题】:Pagination Duplicating Values in RecyclerView in MVVM 【发布时间】:2021-12-15 17:33:18 【问题描述】:我也是 Kotlin MVVM 的新手,我尝试使用旧方法实现分页,但遇到了 RecyclerView 的问题,每当我滚动它时,数据重复,我尝试了 DiffUtils 但没有帮助。
我在 VIEWMODEL 类中记录了数据,数据不重复 但是,当我登录我观察到的 Activity 时,它显示重复值
搜索结果.KT
class SearchResultActivity : AppCompatActivity()
private lateinit var layoutManager: LinearLayoutManager
private lateinit var recyclerView: RecyclerView
private lateinit var pullAdapter: CustomAdapter
private var pageNumber = 1
private var totalItemsCount = 0
private var firstVisibleItemsCount = 0
private var visibleItemsCount = 0
private var previousTotal = 0
private var loading = true
private var fillPullList: ArrayList<RepoPull> = ArrayList()
private var userName: String = ""
private var repoName: String = ""
private var isEnd = false
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
initialize()
getDataPull(userName, repoName)
loadNextData()
private fun initialize()
setContentView(R.layout.activity_search_result)
recyclerView = findViewById(R.id.repoRecView)
layoutManager = LinearLayoutManager(this)
getSearchQuery()
private fun getSearchQuery()
userName = intent.getStringExtra("owner").toString()
repoName = intent.getStringExtra("repo").toString()
populatePullRv()
private fun populatePullRv()
recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
recyclerView.layoutManager = layoutManager
pullAdapter = CustomAdapter(this, fillPullList)
recyclerView.adapter = pullAdapter
progressBar.visibility = View.VISIBLE
private fun loadNextData()
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener()
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int)
super.onScrolled(recyclerView, dx, dy)
val mLayoutManger = recyclerView.layoutManager as LinearLayoutManager
visibleItemsCount = mLayoutManger.childCount
totalItemsCount = mLayoutManger.itemCount
firstVisibleItemsCount = mLayoutManger.findFirstVisibleItemPosition()
if (loading)
if (totalItemsCount > previousTotal)
previousTotal = totalItemsCount
pageNumber++
loading = false
progressBar.visibility = View.GONE
if (!loading && (firstVisibleItemsCount + visibleItemsCount) >= totalItemsCount)
getDataPull(userName, repoName)
loading = true
Log.d("PAGE", pageNumber.toString())
)
private fun getDataPull(username: String?, reponame: String?)
val myViewModel = ViewModelProviders.of(this).get(PullVM::class.java)
myViewModel.endofList.observe(this,
if (it == true)
isEnd = true
progressBar.visibility = View.GONE
Toast.makeText(this@SearchResultActivity, "All PR Fetched", Toast.LENGTH_SHORT)
.show()
)
myViewModel.status.observe(this,
if (it == false)
showError(getString(R.string.no_net))
)
myViewModel.getPullDataFromVM().observe(this,
if (it != null)
listRepos(it) **//DUPLICATE VALUE COMING**
else
showError(getString(R.string.nothing_found))
)
myViewModel.getPullList(username.toString(), reponame.toString(), pageNumber)
private fun showError(s: String)
progressBar.visibility = View.GONE
val theView =
this@SearchResultActivity.findViewById<View>(android.R.id.content)
Snackbar.make(
theView,
s,
Snackbar.LENGTH_LONG
).show()
@SuppressLint("NotifyDataSetChanged")
fun listRepos(repos: List<RepoPull>)
if (!isEnd)
progressBar.visibility = View.GONE
fillPullList.addAll(repos)
pullAdapter.notifyDataSetChanged()
PULLVM(查看模型).kt
class PullVM : ViewModel()
var pullList: MutableLiveData<List<RepoPull>>
var status = MutableLiveData<Boolean?>()
var endofList = MutableLiveData<Boolean?>()
init
pullList = MutableLiveData()
fun getPullDataFromVM(): MutableLiveData<List<RepoPull>>
return pullList
fun getPullList(ownerName: String, repoName: String, pgNo: Int)
val retriever = GitHubRetriever
val callback = object : Callback<List<RepoPull>>
override fun onFailure(call: Call<List<RepoPull>>, t: Throwable)
status.value = false
override fun onResponse(
call: Call<List<RepoPull>>,
response: Response<List<RepoPull>>
)
if (response.body()?.size == 0)
endofList.value = true
if (response.code() == 404)
pullList.postValue(null)
else
status.value = true
val repos = response.body()
if (repos != null)
pullList.postValue(repos)
retriever.userRepos(
callback,
ownerName,
repoName,
pgNo
)
【问题讨论】:
【参考方案1】:尝试将您的 viewModel 实例化和观察者设置移动到 onCreate,这样您就不必创建一个新的 viewModel 实例并为您的 LiveDatas 设置一个新的 observable。
将 myViewModel 声明为 Activity 的 lateinit 属性并将这部分移至 onCreate
myViewModel = ViewModelProviders.of(this).get(PullVM::class.java)
myViewModel.endofList.observe(this,
if (it == true)
isEnd = true
progressBar.visibility = View.GONE
Toast.makeText(this@SearchResultActivity, "All PR Fetched", Toast.LENGTH_SHORT)
.show()
)
myViewModel.status.observe(this,
if (it == false)
showError(getString(R.string.no_net))
)
myViewModel.getPullDataFromVM().observe(this,
if (it != null)
listRepos(it) **//DUPLICATE VALUE COMING**
else
showError(getString(R.string.nothing_found))
)
和
private fun getDataPull(username: String?, reponame: String?)
应该只包含
myViewModel.getPullList(username.toString(), reponame.toString(), pageNumber)
【讨论】:
太棒了!它有效,感谢您的友好回答。能否请您参考链接,以便我可以更有效地学习基础知识 @Xay 这是liveData developer.android.com/topic/libraries/architecture/livedata 的文档和一些示例以及基本示例代码journaldev.com/22561/android-mvvm-livedata-data-binding @Xay 你能把它标记为答案吗?欣赏它。以上是关于MVVM中RecyclerView中的分页重复值的主要内容,如果未能解决你的问题,请参考以下文章
分页不适用于 NestedScrollView 中的 RecyclerView