我正在 recyclerview 中实现 recyclerview ,如下图所示,并使用 diffutil asynclistdiffer 来管理列表元素中的更改。
在下面添加片段和适配器的代码。
自定义事件片段代码:
class CustomizeEventFragment : Fragment(){
private lateinit var mContext: Context
private lateinit var viewModel: CustomizeEventViewModel
private lateinit var customizeEventRecyclerAdapter: CustomizeEventRecyclerAdapter
companion object {
fun newInstance() = CustomizeEventFragment()
}
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.customize_event_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.d("App", "Inside onviewcreated customize event fragment")
viewModel = activity?.let { ViewModelProvider(it).get(CustomizeEventViewModel::class.java) }!!
subscibeObservers()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Log.d("App", "Inside onactivity created of customize event fragment")
}
private fun subscibeObservers(){
viewModel.customizeEventList.observe(viewLifecycleOwner, Observer {
it?.let {
rv_customizeEvents.apply {
layoutManager = LinearLayoutManager(mContext)
customizeEventRecyclerAdapter = CustomizeEventRecyclerAdapter(null, viewModel)
adapter = customizeEventRecyclerAdapter
setHasFixedSize(true)
}
customizeEventRecyclerAdapter.submitList(it)
}
})
}}
CustomizeEventRecyclerAdapter 代码:
class CustomizeEventRecyclerAdapter(private val interaction: Interaction? = null, val viewModel: CustomizeEventViewModel) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<CustomizeEventModel>() {
override fun areItemsTheSame(oldItem: CustomizeEventModel, newItem: CustomizeEventModel): Boolean {
return oldItem.eventModel.eventName == newItem.eventModel.eventName
}
override fun areContentsTheSame(oldItem: CustomizeEventModel, newItem: CustomizeEventModel): Boolean {
return oldItem ==newItem
}
}
private val differ = AsyncListDiffer(this, DIFF_CALLBACK)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ListViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_customized_event,
parent,
false
),
interaction
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ListViewHolder -> {
Log.d("App", "Inside onbindviewholder adapter")
holder.bind(differ.currentList.get(position))
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
fun submitList(list: List<CustomizeEventModel>) {
Log.d("App", "Inside submit list" + list.toString())
differ.submitList(list)
}
inner class ListViewHolder
constructor(
itemView: View,
private val interaction: Interaction?
) : RecyclerView.ViewHolder(itemView), SelectedItemsRecyclerAdapter.Interaction {
fun bind(item: CustomizeEventModel) = with(itemView) {
itemView.tv_cardEventTitle.text = item.eventModel.eventName
if (item.eventModel.member2.equals("")){
itemView.tv_cardMembers.text = "Members: ${item.eventModel.member1}"
}else{
itemView.tv_cardMembers.text = "Members: ${item.eventModel.member1}, ${item.eventModel.member2}"
}
if (item.selectedCake.itemName.equals("")){
itemView.btn_selectCake.setText("Select Cake")
}else{
itemView.btn_selectCake.setText(item.selectedCake.itemName)
}
itemView.btn_selectCake.setOnClickListener {
val action: NavDirections = CustomizeEventFragmentDirections.actionCustomizeEventFragmentToBottomSheetCakeFragment(adapterPosition)
Navigation.findNavController(it).navigate(action)
}
itemView.btn_addItem.setOnClickListener {
val action: NavDirections = CustomizeEventFragmentDirections.actionCustomizeEventFragmentToBottomSheetAddItemsFragment(adapterPosition)
Navigation.findNavController(it).navigate(action)
}
if (!item.selectedweight.equals("")){
itemView.weightSelection.setText(item.selectedweight)
}
val weights: ArrayList<String> = ArrayList()
val variants = item.selectedCake.variant
for (i in variants){
weights.add(i.weight)
}
val adspinner = ArrayAdapter(context, R.layout.item_citytext, weights)
(itemView.weightSelection as? AutoCompleteTextView)?.setAdapter(adspinner)
itemView.weightSelection.setOnItemClickListener { parent, view, position, id ->
viewModel.updateSelectedWeight(parent.getItemAtPosition(position).toString(), adapterPosition)
}
val selectedItemsRecyclerAdapter: SelectedItemsRecyclerAdapter
rv_itemList.apply {
layoutManager = LinearLayoutManager(context.applicationContext)
selectedItemsRecyclerAdapter = SelectedItemsRecyclerAdapter(this@ListViewHolder)
adapter = selectedItemsRecyclerAdapter
setHasFixedSize(true)
}
if (!item.selectedItems.isNullOrEmpty()){
selectedItemsRecyclerAdapter.submitList(item.selectedItems.toList())
}
}
override fun onItemRemoved(itemPosition: Int) {
viewModel.removeSelectedItem(itemPosition, adapterPosition)
}
}
interface Interaction {
fun onItemSelected(position: Int)
}}
如附加的屏幕截图所示,当单击添加项目按钮时,另一个适配器被调用以设置选定项目的列表,我们也可以在单击“X”按钮时删除这些项目。SelectedItemsRecyclerAdapter 代码:
class SelectedItemsRecyclerAdapter(private val interaction: Interaction? = null) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ProductModel>() {
override fun areItemsTheSame(oldItem: ProductModel, newItem: ProductModel): Boolean {
return oldItem.itemName == newItem.itemName
}
override fun areContentsTheSame(oldItem: ProductModel, newItem: ProductModel): Boolean {
return oldItem == newItem
}
}
private val differ = AsyncListDiffer(this, DIFF_CALLBACK)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return ListViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_selected_items,
parent,
false
),
interaction
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ListViewHolder -> {
holder.bind(differ.currentList.get(position))
}
}
}
override fun getItemCount(): Int {
return differ.currentList.size
}
fun submitList(list: List<ProductModel>) {
differ.submitList(list)
}
inner class ListViewHolder
constructor(
itemView: View,
private val interaction: Interaction?
) : RecyclerView.ViewHolder(itemView) {
fun bind(item: ProductModel) = with(itemView) {
itemView.tv_itemName.text = item.itemName
itemView.iv_removeItem.setOnClickListener {
interaction?.onItemRemoved(adapterPosition)
}
}
}
interface Interaction {
fun onItemRemoved(itemPosition: Int)
}}
自定义事件视图模型代码:
class CustomizeEventViewModel(application: Application) : AndroidViewModel(application) {
var customizeEventList = MutableLiveData<List<CustomizeEventModel>>()
fun updateCustomizeEventList(selectedEvents: List<EventModel>){
val _customizeEventList: MutableList<CustomizeEventModel> = mutableListOf()
for (item in selectedEvents){
val _customizeEventModel = CustomizeEventModel(item)
_customizeEventList.add(_customizeEventModel)
}
customizeEventList.value = _customizeEventList.toList()
}
fun updateSelectedCake(model: ProductModel, position: Int){
val _customizeEventList: MutableList<CustomizeEventModel>? = customizeEventList.value as MutableList<CustomizeEventModel>?
val customizeEventModel: CustomizeEventModel = _customizeEventList?.get(position)!!
customizeEventModel.selectedCake = model
_customizeEventList.set(position, customizeEventModel)
customizeEventList.value = _customizeEventList.toList()
}
fun updateSelectedWeight(weight: String, adPosition: Int){
val _customizeEventList: MutableList<CustomizeEventModel>? = customizeEventList.value as MutableList<CustomizeEventModel>?
val customizeEventModel: CustomizeEventModel = _customizeEventList?.get(adPosition)!!
customizeEventModel.selectedweight = weight
_customizeEventList.set(adPosition, customizeEventModel)
customizeEventList.value = _customizeEventList.toList()
}
fun updateSelectedItem(item: ProductModel, position: Int){
val _customizeEventList: MutableList<CustomizeEventModel>? = customizeEventList.value as MutableList<CustomizeEventModel>?
val itemList: ArrayList<ProductModel> = _customizeEventList?.get(position)?.selectedItems!!
itemList.add(item)
val customizeEventModel: CustomizeEventModel = _customizeEventList.get(position)
customizeEventModel.selectedItems = itemList
_customizeEventList.set(position, customizeEventModel)
customizeEventList.value = _customizeEventList.toList()
}
fun removeSelectedItem (itemPosition: Int, adPosition: Int){
val _customizeEventList: MutableList<CustomizeEventModel>? = customizeEventList.value as MutableList<CustomizeEventModel>?
val itemList: ArrayList<ProductModel> = _customizeEventList?.get(adPosition)?.selectedItems!!
itemList.removeAt(itemPosition)
val customizeEventModel: CustomizeEventModel = _customizeEventList.get(adPosition)
customizeEventModel.selectedItems = itemList
_customizeEventList.set(adPosition, customizeEventModel)
customizeEventList.value = _customizeEventList.toList()
}}
问题描述: 在 CustomizeEventFragment 中,当对任何事件卡执行 Select cake、Add items 或 Remove selected Items 的操作时,然后在观察者内部我调用 CustomizeEventAdapters submitlist 方法并每次都传递更新的列表。因此,每当列表数据更改/更新时,都会调用观察者,但这会导致整个回收视图更新它的 UI,如 notifydatasetchanged。我认为这是因为我正在初始化观察者内部的 recyclerview 和适配器。
当假设我对第三个事件卡执行任何操作时,这会导致问题,然后在观察者因该更改而受到打击后,它会导致整个 recyclerview 更新其 UI 并且 recyclerview 中的项目从第一个初始位置显示。在 recyclerview 更新后,它应该保持在第 3 个事件卡位置。
我尝试在观察者之外删除以下 recyclerview 和适配器初始化代码
rv_customizeEvents.apply {
layoutManager = LinearLayoutManager(mContext)
customizeEventRecyclerAdapter = CustomizeEventRecyclerAdapter(null, viewModel)
adapter = customizeEventRecyclerAdapter
setHasFixedSize(true)
}
但是当我这样做时,仅在观察者内部调用 customizeEventRecyclerAdapter submitlist 方法不会检测/更新 recyclerview UI 以更改列表。Diffutil asynclistdiffer submitlist 方法应该处理更改,但我无法理解为什么它没有按预期工作。请指出我在片段/适配器代码或视图模型实现中犯的任何错误。