首页 > 解决方案 > Android RecyclerView submitList 未更新 LiveData 观察者中的数据

问题描述

我正在尝试使用 LiveData Observer 中的 submitList 更新我的嵌套 RecyclerView 列表。列表已提交,但 UI 仅在您触摸屏幕时更新。当我在我的主 RecyclerView 中添加嵌套的 RecyclerViews 时,问题就出现了。所以我认为这与它有关。

我希望它在调用 submitList 后更新。我究竟做错了什么?

外部列表适配器:

class ReservationAdapter(
        private val changeState: (visit: Visit, newState: Visit.State) -> MutableLiveData<Visit?>
) : ListAdapter<Reservation, ReservationViewHolder>(ReservationDiffCallback()) {
    private val recycledViewPool = RecyclerView.RecycledViewPool()

    /// Filters \\\
    // Building
    var filterBuildingId = ""
        set(value) {
            field = value
            filteredVisits = visits.filter(Visit.filter(value, filterSearchString))
        }

    // Search string
    var filterSearchString = ""
    set(value) {
        field = value
        filteredVisits = visits.filter(Visit.filter(filterBuildingId, value))
    }

    /// Filtering chain \\\
    // Visits come in and get filtered
    var visits = arrayListOf<Visit>()
        set(value) {
            field = value
            filteredVisits = value.filter(Visit.filter(filterBuildingId, filterSearchString))
        }

    // Filtered visits come in, a reservation map is made
    var filteredVisits = listOf<Visit>()
        set(value) {
            field = value
            reservationVisits = Reservation.extractMapFromVisits(value)
        }

    // Reservation map comes in, and submits a list of reservations
    private var reservationVisits = hashMapOf<Reservation, ArrayList<Visit>>()
        set(value) {
            field = value
            _reservationVisits.value = value
            submitList(value.keys.toMutableList())
            notifyDataSetChanged()
        }
    private val _reservationVisits = MutableLiveData<HashMap<Reservation, ArrayList<Visit>>>()


    /**
     * Inflate items
     */
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReservationViewHolder {
        return ReservationViewHolder(
                LayoutInflater.from(parent.context).inflate(
                        R.layout.list_reservation,
                        parent,
                        false
                ),
                recycledViewPool,
                changeState,
                _reservationVisits
        )
    }

    /**
     * Bind items
     */
    override fun onBindViewHolder(holder: ReservationViewHolder, position: Int) {
        val reservation = getItem(position)
        holder.bind(reservation, reservationVisits[reservation])
    }
}

外部 ViewHolder:

class ReservationViewHolder(
        private val view: View,
        private val recycledViewPool: RecyclerView.RecycledViewPool,
        changeState: (visit: Visit, newState: Visit.State) -> MutableLiveData<Visit?>,
        reservationVisits: MutableLiveData<HashMap<Reservation, ArrayList<Visit>>>
) : RecyclerView.ViewHolder(view) {
    private val adapter = VisitAdapter(changeState)
    private var _reservation: Reservation? = null

    init {
/*
THIS IS WHERE I SETS THE VALUE, BUT DOESN'T UPDATE THE UI.
*/
        reservationVisits.observe(view.context as LifecycleOwner) {
            if (_reservation != null) {
                (view.context as MainActivity).runOnUiThread {
                    adapter.submitList(null)
                    adapter.notifyDataSetChanged()
                    adapter.submitList(it[_reservation!!]?.toMutableList())
                    adapter.notifyDataSetChanged()
                    view.refreshDrawableState()
                }
            }
        }
    }

    fun bind(reservation: Reservation, visits: ArrayList<Visit>?): View = with(view) {
        println("3: ${visits?.size}")
        _reservation = reservation
        // Initialize values
        txtSubject.text = reservation.subject
        txtTime.text = "TIME"
        // Recycler view for visits
        rcvVisits.apply {
            (itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
            layoutManager = LinearLayoutManager(context)
            adapter = this@ReservationViewHolder.adapter
            setRecycledViewPool(this@ReservationViewHolder.recycledViewPool)
        }

        // Add visits to adapter
        adapter.submitList(visits)

        // Return view
        view
    }
}

内部列表适配器:

class VisitAdapter(
        private val changeState: (visit: Visit, newState: Visit.State) -> MutableLiveData<Visit?>
) : ListAdapter<Visit, VisitViewHolder>(VisitDiffCallback()) {
    // Sorter
    private val _visitSorter = compareBy<Visit>({ it.state }, { it.expectedArrival }, { it.visitor?.name })

    // ListAdapter create
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VisitViewHolder {
        return VisitViewHolder(
                LayoutInflater.from(parent.context).inflate(
                        R.layout.list_visitor,
                        parent,
                        false
                ),
                changeState
        )
    }

    // ListAdapter bind
    override fun onBindViewHolder(holder: VisitViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    // ListAdapter submit
    override fun submitList(list: List<Visit>?) {
        super.submitList(list?.sortedWith(_visitSorter) ?: listOf())
    }
}

标签: androidkotlinandroid-recyclerviewandroid-viewholdermutablelivedata

解决方案


我检查了你的代码,这些是我发现的:

您在视图持有者类中创建了适配器和观察者的实例。

视图持有者将实例化多次,因此您不应在其中实例化适配器。检查这个链接

如果你想将数据传递给你的视图持有者,你应该在构造函数中进行,永远不要观察视图持有者类中的数据变化。

这样您就可以观察活动中的数据并将数据传递给您的适配器。

并且无需召集runOnUiThread观察员。它已经在主线程(UI 线程)上。

事件在主线程上调度。如果 LiveData 已经有数据集,它将被传递给观察者。 实时数据


推荐阅读