Android RecyclerView submitList не обновляет данные в обозревателе LiveData - PullRequest
1 голос
/ 22 января 2020

Я пытаюсь обновить свой вложенный список RecyclerView, используя submitList в LiveData Observer. Список отправляется, но пользовательский интерфейс обновляется только при касании экрана. Проблема возникла, когда я добавил вложенные RecyclerViews в свой основной RecyclerView. Поэтому я думаю, что это как-то связано с этим.

Я хочу обновить его после вызова submitList. Что я делаю не так?

Внешний ListAdapter:

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
    }
}

Внутренний ListAdapter:

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())
    }
}

Ответы [ 2 ]

0 голосов
/ 23 января 2020

Я решил это. Проблема была с библиотекой com.mikepenz:aboutlibraries:7.0.4@aar.

После того, как я удалил ее и закомментировал любой код, который его использовал, он начал работать.

0 голосов
/ 22 января 2020

Я проверил ваш код, вот что я нашел:

вы создали экземпляр адаптера и наблюдателя в классе держателя представления.

держатель представления будет создан несколько раз, поэтому вы не должны инстанцировать адаптер в нем. проверьте эту ссылку

, и если вы хотите передать данные в свой держатель представления, вы должны сделать это в конструкторе, никогда не наблюдать за изменением данных в классе держателя представления.

так что вы можете наблюдать данные в действии и передавать данные в ваш адаптер.

и нет необходимости вызывать runOnUiThread в наблюдателе. он уже находится в главном потоке (поток пользовательского интерфейса).

События отправляются в основной поток. Если LiveData уже имеет набор данных, он будет доставлен наблюдателю. LiveData

...