Diffutil asynclist Другой метод списка отправки не работает должным образом
Я реализую recyclerview внутри recyclerview, как показано на изображении ниже, и использую diffutilasynclistdiffer для управления изменениями в элементах списка.
Добавляем код фрагмента и адаптеров ниже.
Код CustomizeEventFragment:
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)
}}
Код CustomizeEventViewModel:
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, когда действие для выбора торта, добавления элементов или удаления выбранных элементов выполняется для любой карточки события, внутри наблюдателя я вызываю метод списка отправки CustomizeEventAdapters и каждый раз передаю обновленный список. Таким образом, каждый раз, когда данные списка изменяются / обновляются, вызывается наблюдатель, но это заставляет весь recyclerview обновлять его пользовательский интерфейс, например notifydatasetchanged. Я думаю, что это происходит потому, что я инициализирую recyclerview и адаптер внутри наблюдателя.
Это вызывает проблему, если предположить, что я выполняю какое-либо действие с 3-й картой события, а затем после того, как наблюдатель получает удар для этих изменений, он заставляет весь recyclerview обновлять свой пользовательский интерфейс, а элементы в recyclerview отображаются с первой начальной позиции.
Я попытался удалить приведенный ниже код инициализации recyclerview и адаптера вне наблюдателя.
rv_customizeEvents.apply {
layoutManager = LinearLayoutManager(mContext)
customizeEventRecyclerAdapter = CustomizeEventRecyclerAdapter(null, viewModel)
adapter = customizeEventRecyclerAdapter
setHasFixedSize(true)
}
Но когда я это делаю, вызов только метода списка отправки customizeEventRecyclerAdapter внутри наблюдателя не обнаруживает / не обновляет пользовательский интерфейс recyclerview в измененный список. Метод Diffutilasynclistdiffer submitlist должен обрабатывать изменения, но я не могу понять, почему он не работает должным образом. Пожалуйста, укажите на любую ошибку, которую я делаю в моем коде фрагмента / адаптера или реализации модели представления.