简体   繁体   中英

RecyclerView is not updating itself when submiting new list

I couldn't be able to update UI of recyclerview when I submit new list of data, I also have other recyclerViews in my app but they all have LinearLayoutManager but this one has GridLayoutManager, Maybe this can be a cause, but the point here is I have done everything but I couldn't find the problem why my recyclerView is updating the UI.

Note: I have confirmed the data logic, it is submitting a different list for updatation.

The flow is simple When a user click on the photo the photo get deleted and a new list from LiveData get observed and I have seen the logs and it is submitting new list with excluding the deleted photo.

XML of fragment

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="vViewModel"
            type="com.android.example.presentation.pack.visit.VisitViewModel" />
    </data>
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".presentation.pack.visit.VisitFragment">
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rvPackPhotos"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"/>
    </FrameLayout>
</layout>

Fragment


class VisitFragment : Fragment() {
    private val viewModel: VisitViewModel by viewModels()
    private lateinit var binding: FragmentVisitBinding
    private var packId: Int? = null

    private lateinit var adapter: PhotosAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            packId = it.getInt("packId")
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_visit, container, false)

        adapter = PhotosAdapter(PhotoClickListener {
            viewModel.deleteImage(it)
        })
        val manager = GridLayoutManager(activity, 4, GridLayoutManager.VERTICAL, false)
        binding.rvPackPhotos.adapter = adapter
        binding.rvPackPhotos.layoutManager = manager
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.vViewModel = viewModel
        binding.lifecycleOwner = viewLifecycleOwner
        packId?.let {
            viewModel.setArgPackId(it)
        }

        setObservers()
    }

    private fun setObservers() {
        viewModel.apply {
            mediaList.observe(viewLifecycleOwner) {
                it?.let {
                    println("media length now: ${it.size}")
                    println(it)
                    adapter.submitList(it)
                }
            }
        }
    }
}

PhotosAdapter


class PhotosAdapter(
    private val clickListener: PhotoClickListener
) : ListAdapter<Media, PhotosAdapter.ViewHolder>(DiffCallBack()) {
    class DiffCallBack : DiffUtil.ItemCallback<Media>() {
        override fun areItemsTheSame(oldItem: Media, newItem: Media): Boolean {
            return oldItem.mediaUrl == newItem.mediaUrl
        }

        override fun areContentsTheSame(oldItem: Media, newItem: Media): Boolean {
            return oldItem == newItem
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder.from(parent)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position)!!, clickListener, position)
    }

    class ViewHolder private constructor(private val binding: ItemPackPhotosBinding)
        : RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Media, clickListener: PhotoClickListener, position: Int) {
            binding.media = item
            binding.clickListener = clickListener
            binding.position = position
        }

        companion object {
            fun from(parent: ViewGroup): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val binding = ItemPackPhotosBinding.inflate(layoutInflater, parent, false)
                return ViewHolder(binding)
            }
        }
    }
}

class PhotoClickListener(private val clickListener: (mediaUrl: String) -> Unit) {
    fun onClick(mediaUrl: String) = clickListener(mediaUrl)
}

ViewModel

private val _mediaList = MutableLiveData<MutableList<Media>>()
val mediaList : LiveData<MutableList<Media>>
    get() = _mediaList

fun deleteImage(mediaUrl: String) {
    viewModelScope.launch {
        val res = packRepository.postDeleteImage(
            DeleteImageRequest(
                mediaUrl = mediaUrl,
                parent = _packData.value!!.packId
            )
        )
        if (res) {
            val copy = _mediaList.value!!
            copy.removeIf { it.mediaUrl == mediaUrl}
            _mediaList.postValue(copy)
        }
    }
}

I used your code (just copy-paste) to create an app, it works for me.

In Fragment:

Creating adapter:

adapter = PhotosAdapter(PhotoClickListener { mediaUrl ->
    viewModel.deleteImage(mediaUrl)
})

Observing items:

viewModel.mediaList.observe(viewLifecycleOwner) { items ->
    items?.let {
        adapter.submitList(it)
    }
}

In ViewModel

Field (from ViewModel) do be observe in Fragment:

private val _mediaList = MutableLiveData<List<Media>>()
val mediaList: LiveData<List<Media>>
    get() = _mediaList

Method do remove item from items and set new value:

fun deleteImage(mediaUrl: String) {
    val list = _mediaList.value?.toMutableList() ?: mutableListOf()

    list.removeIf { item -> item.mediaUrl == mediaUrl }

    _mediaList.postValue(list)
}

Video:

视频

Download project example:

https://www.mediafire.com/file/2dttm1hs70qehx2/stackoverflow.zip/file

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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