大佬教程收集整理的这篇文章主要介绍了带有 DiffUtil 更新,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
如何使用 DiffUtil 回调处理 RecyclerVIEw 的 onClick?以及如何在 recyclervIEw 中更改所选项目的背景颜色?我在一个活动中有两个 RecyclerVIEws。当用户点击 RecyclerVIEw A 中的项目时,RecyclerVIEw B 中会发生一些事情。
这是课堂
import androIDx.room.columnInfo
data class SkladTuple(
@columnInfo(name = "sklad") val sklad: Int?,@columnInfo(name = "reg") val reg: Int?
)
这是适配器:
class SkladAdapter: listadapter<SkladTuple,SkladAdapter.PolozkaVIEwHolder>(DiffCallBACk())
{
overrIDe fun onCreateVIEwHolder(parent: VIEwGroup,vIEwType: int): PolozkaVIEwHolder {
val binding = SkladyItembinding.inflate(LayoutInflater.from(parent.context),parent,falsE)
return PolozkaVIEwHolder(binding)
}
overrIDe fun onBindVIEwHolder(holder: PolozkaVIEwHolder,position: int) {
val currentItem = getItem(position)
holder.bind(currentItem)
}
class PolozkaVIEwHolder(private val binding: SkladyItembinding): RecyclerVIEw.VIEwHolder(binding.root){
fun bind(polozkaSklad: SkladTuplE){
binding.apply {
tvSklad.text = polozkaSklad.sklad.toString()
tvRegal.text = polozkaSklad.reg.toString()
}
}
}
class DiffCallBACk: DiffUtil.ItemCallBACk<SkladTuple>(){
overrIDe fun areItemsTheSame(oldItem: SkladTuple,newItem: SkladTuplE) =
oldItem.sklad == newItem.sklad
overrIDe fun areContentsTheSame(oldItem: SkladTuple,newItem: SkladTuplE) =
oldItem == newItem
}
}
这是活动
@AndroIDEntryPoint
class DokladActivity : AppCompatActivity() {
private val skladviewmodel: Skladviewmodel by viewmodels()
overrIDe fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceStatE)
val binding = ActivityDokladBinding.inflate(layoutInflater)
setContentVIEw(binding.root)
binding.btVybratDoklad.setonClickListener{
openActivity(binding.root)
}
val skladAdapter = SkladAdapter()
val dokladAdapter = DokladAdapter()
binding.apply {
recyclerVIEwSklady.apply {
adapter = skladAdapter
layoutManager = linearlayoutmanager(this@DokladActivity)
}
skladviewmodel.skladyPolozky.observe(this@DokladActivity) {
skladAdapter.submitList(it)
Log.d("Doklad",skladAdapter.currentList.toString())
}
recyclerVIEwDoklady.apply {
adapter = dokladAdapter
layoutManager = linearlayoutmanager(this@DokladActivity)
}
skladviewmodel.dokladyPolozky.observe(this@DokladActivity){
dokladAdapter.submitList(it)
Log.d("Doklad",dokladAdapter.currentList.toString())
}
}
}
fun openActivity(vIEw: VIEw){
val intent = Intent(this,PolozkaActivity::class.java )
startActivity(intent)
}
}
这是视图模型
@Hiltviewmodel
class Skladviewmodel @Inject constructor(
repository: SybaseRepository
): viewmodel(){
val skladyPolozky = repository.getAllSkladFromPolozka().asliveData()
val dokladyPolozky = repository.getAllHlavickyTodoklad().asliveData()
}
这是布局 - 我有两个回收站视图。当用户点击 recyclervIEw A 中的项目时,recyclervIEw B 中会发生一些事情
<?xml version="1.0" enCoding="utf-8"?>
<androIDx.consTraintlayout.Widget.ConsTraintLayout xmlns:androID="http://scheR_235_11845@as.androID.com/apk/res/androID"
xmlns:app="http://scheR_235_11845@as.androID.com/apk/res-auto"
xmlns:tools="http://scheR_235_11845@as.androID.com/tools"
androID:layout_wIDth="match_parent"
androID:layout_height="match_parent">
<androIDx.consTraintlayout.Widget.GuIDeline
androID:ID="@+ID/guIDeline8"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:orIEntation="horizontal"
app:layout_consTraintGuIDe_percent="0.02" />
<androIDx.consTraintlayout.Widget.GuIDeline
androID:ID="@+ID/guIDeline9"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:orIEntation="vertical"
app:layout_consTraintGuIDe_percent="0.7" />
<androIDx.consTraintlayout.Widget.GuIDeline
androID:ID="@+ID/guIDeline10"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:orIEntation="horizontal"
app:layout_consTraintGuIDe_percent="0.25" />
<androIDx.consTraintlayout.Widget.GuIDeline
androID:ID="@+ID/guIDeline11"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:orIEntation="horizontal"
app:layout_consTraintGuIDe_percent="0.75" />
<androIDx.consTraintlayout.Widget.GuIDeline
androID:ID="@+ID/guIDeline12"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:orIEntation="horizontal"
app:layout_consTraintGuIDe_percent="0.9" />
<tableLayout
androID:stretchcolumns="1,2"
androID:layout_margin="8dp"
androID:layout_wIDth="0dp"
androID:layout_height="0dp"
androID:layout_marginStart="8dp"
androID:layout_margintop="8dp"
androID:layout_marginEnd="8dp"
androID:layout_marginBottom="8dp"
app:layout_consTraintBottom_totopOf="@+ID/guIDeline10"
app:layout_consTraintEnd_toStartOf="@+ID/guIDeline9"
app:layout_consTraintStart_toStartOf="parent"
app:layout_consTrainttop_totopOf="@+ID/guIDeline8">
<tableRow>
<TextVIEw
androID:text="SKLAD"
androID:textSize="16dp"
androID:textStyle="bold"
androID:padding="10dp"
androID:layout_gravity="center"
androID:layout_column="1"/>
<TextVIEw
androID:text="REgal"
androID:textSize="16dp"
androID:textStyle="bold"
androID:padding="10dp"
androID:layout_gravity="center"
androID:layout_column="1"/>
</tableRow>
<androIDx.recyclervIEw.Widget.RecyclerVIEw
xmlns:app="http://scheR_235_11845@as.androID.com/apk/res-auto"
androID:ID="@+ID/recycler_vIEw_sklady"
androID:scrollbars="vertical"
androID:layout_wIDth="match_parent"
androID:layout_height="wrap_content"
tools:Listitem="@layout/sklady_item"
/>
</tableLayout>
<tableLayout
androID:layout_wIDth="0dp"
androID:layout_height="0dp"
androID:layout_marginStart="8dp"
androID:layout_margintop="8dp"
androID:layout_marginEnd="16dp"
androID:layout_marginBottom="8dp"
androID:stretchcolumns="1,2,3,4,5"
app:layout_consTraintBottom_totopOf="@+ID/guIDeline11"
app:layout_consTraintEnd_toEndOf="parent"
app:layout_consTraintStart_toStartOf="parent"
app:layout_consTrainttop_totopOf="@+ID/guIDeline10"
>
<tableRow>
<TextVIEw
androID:layout_column="1"
androID:layout_gravity="center"
androID:padding="10dp"
androID:text="U"
androID:textSize="16dp"
androID:textStyle="bold" />
<TextVIEw
androID:layout_column="1"
androID:layout_gravity="center"
androID:padding="10dp"
androID:text="DOKL"
androID:textSize="16dp"
androID:textStyle="bold" />
<TextVIEw
androID:layout_column="1"
androID:layout_gravity="center"
androID:padding="10dp"
androID:text="ODB"
androID:textSize="16dp"
androID:textStyle="bold" />
<TextVIEw
androID:layout_column="1"
androID:layout_gravity="center"
androID:padding="10dp"
androID:text="ORG"
androID:textSize="16dp"
androID:textStyle="bold" />
<TextVIEw
androID:layout_column="1"
androID:layout_gravity="center"
androID:padding="10dp"
androID:text="DATUM"
androID:textSize="16dp"
androID:textStyle="bold" />
</tableRow>
<androIDx.recyclervIEw.Widget.RecyclerVIEw
xmlns:app="http://scheR_235_11845@as.androID.com/apk/res-auto"
androID:ID="@+ID/recycler_vIEw_doklady"
androID:scrollbars="vertical"
androID:layout_wIDth="match_parent"
androID:layout_height="wrap_content"
tools:Listitem="@layout/doklady_item"/>
</tableLayout>
<button
androID:ID="@+ID/bT_Back"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_marginStart="24dp"
androID:text="Zpět"
app:layout_consTraintBottom_toBottomOf="parent"
app:layout_consTraintStart_toStartOf="parent"
app:layout_consTrainttop_totopOf="@+ID/guIDeline12" />
<button
androID:ID="@+ID/bt_vybrat_doklad"
androID:layout_wIDth="wrap_content"
androID:layout_height="wrap_content"
androID:layout_marginEnd="24dp"
androID:text="Vybrat doklad"
app:layout_consTraintBottom_toBottomOf="parent"
app:layout_consTraintEnd_toEndOf="parent"
app:layout_consTrainttop_totopOf="@+ID/guIDeline12" />
<TextVIEw
androID:ID="@+ID/textVIEw2"
androID:layout_wIDth="209dp"
androID:layout_height="50dp"
androID:layout_marginStart="24dp"
androID:layout_margintop="16dp"
androID:text="TextVIEw"
app:layout_consTraintBottom_totopOf="@+ID/guIDeline12"
app:layout_consTraintEnd_toStartOf="@+ID/guIDeline9"
app:layout_consTraintStart_toStartOf="parent"
app:layout_consTrainttop_totopOf="@+ID/guIDeline11" />
</androIDx.consTraintlayout.Widget.ConsTraintLayout>
怎么可能……
您有一个 ViewModel,它使用 RecyclerViews 需要的 List(两个适配器,两个列表)公开了两个可观察的 liveData。
决定List A,Item 1被点击,因此List B,Item N必须改变背景的逻辑绝对超出 Recycler View,Adapter,Activity,甚至可能是 ViewModel。
最终,当发生数据突变时(您点击了第 1 项),您会收到此事件,对其采取行动(又名:将其发送到 Viewmodel -> Repository -> 转换数据 ->发布包含变异数据的新列表。
最终,您的 ViewModel 将从存储库接收新数据,并将更新您的活动正在观察的 LiveData(s),这将导致适配器提交新数据,您的 DiffUtils 将获取这些数据,导致Adapter 重新绑定修改后的视图。
根据您链接的问题/答案以及您的评论,我认为这值得进一步评论。
此人说:“处理适配器上的点击或使用接口都不是一个好主意”,然后继续“处理”点击,和使用匿名函数(所以它可能是一个用于测试目的的接口,但它使它成为一个“高阶函数”。
这和我描述的原理完全一样,只是接口更容易理解。
想想这样的责任:
ViewHolder:它对数据、回收器视图、适配器等一无所知。但它可以直接访问列表的每个“行/列”。它拥有视图,并且可以根据它提供的数据来操纵它们,并被告知“保留”在所需的视图旁边。它不创建视图(它被告知)但它有它们。关于点击,所有这些可以做的是公开一个视图(这样一个点击侦听器可以由外部设置)或简单地委托它。
Adapter:除了视图的类型(如果使用)以及如何创建 viewHolders 和“绑定”它们之外,它对视图一无所知。所以它介于两者之间,但它确实可以访问提供给它的数据源(您提供的列表),并且它确实可以访问它创建的每个“视图持有者”;它或多或少知道屏幕上的内容,并且可以将位置映射到数据。
RecyclerView/Fragment/ViewModel:它们不知道适配器内部发生了什么(也不应该),但它们主要对点击(或事件)何时发生感兴趣,因此它们大概可以对此做些什么。
基于所有这些,让我们看看 this person's solution(对比我的建议):
(private val onSELEct: (YourDataType?) -> Unit)
我通常定义一个接口:
interface SomethingClickListener {
fun onSomethingICaredForHappened(something: Something)
}
并将其传递给我的适配器,但想法是相同的;我更喜欢这个界面,因为它更容易对具体类型使用依赖注入(并且更容易测试),但这只是我个人的偏好。
class YourAdapter(private val clickListener: SomethingClickListener)
通过简单地使用单击侦听器的匿名实现并捕获发送到绑定方法的值(很好),您可以(或想要在那里做更多的事情),链接的答案就消失了。所以你可以使用另一个界面或这样做,本质上,想法是一样的,你正在传递点击事件。
binding.root.setOnClickListener {
onSELEct(yourDataTypE)
}
因此它将 dataType
直接传递给 onSELEct
(这是提供给适配器的函数)。在这个阶段,其中唯一的逻辑是附加与被点击的 viewBinding 相关联的“数据”,这是适配器/视图持有者可以并且应该提供的“唯一”信息。
在此 onSELEct
之后会发生什么,是您的片段/活动收到此信息,然后您应该调用您的 ViewModel 说:
viewModel.thisThingWasClicked(theThingYouReceived)
你明白了……
我有一段时间没有更新它(我想我是 3 年前用 Java 写的,然后我天真地将它转换为 Kt)除了更新库并确保它仍然可以编译,但是你可以看到“两个接口方法”(现在有点老派,可以通过 Kotlin 使用高阶函数),但仍然是相同的方法。
看看这个项目(特别是 adapter。
请注意,它接受 ThingClickListener
,但在内部使用 ToggleListener
在 ViewHolders 和适配器之间进行通信。
最后,这可以简化为使用更少的界面。
我希望这能澄清这个想法。 请注意,除了处理 Click 侦听器和绑定正确数据之外,ViewHolder 和 Adapter 都没有任何责任。
以上是大佬教程为你收集整理的带有 DiffUtil 更新全部内容,希望文章能够帮你解决带有 DiffUtil 更新所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。