Android RecyclerView submitList 未更新 LiveData 观察器中的数据

Android RecyclerView submitList not updating data in LiveData observer

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

我希望它在调用 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())
    }
}

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

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

view holder 会多次实例化,所以你不应该在其中实例化适配器。检查这个 link

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

因此您可以观察 activity 中的数据并将数据传递给您的适配器。

并且不需要在观察者中调用 runOnUiThread。它已经在主线程上(UI 线程)。

The events are dispatched on the main thread. If LiveData already has data set, it will be delivered to the observer. LiveData

我解决了。 问题出在 com.mikepenz:aboutlibraries:7.0.4@aar 库上。

在我删除它并注释掉所有使用它的代码后,它开始工作了。