Reputation: 11
I am trying to update my nested RecyclerView list using submitList in a LiveData Observer. The list is submitted, but the UI only updates when you touch the screen. The issue arose when I added nested RecyclerViews in my master RecyclerView. So I think it has something to do with it.
I want it to update after the submitList is called. What am I doing wrong?
Outer 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])
}
}
Outer 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 = [email protected]
setRecycledViewPool([email protected])
}
// Add visits to adapter
adapter.submitList(visits)
// Return view
view
}
}
Inner 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())
}
}
Upvotes: 1
Views: 2290
Reputation: 11
I solved it.
The issue was with the com.mikepenz:aboutlibraries:7.0.4@aar
library.
After I removed it and commented out any code that used it, it started working.
Upvotes: 0
Reputation: 2164
I checked your code these are what I found:
you created an instance of the adapter and an observer in view holder class.
view holder will instantiate multiple times, so you shouldn't instantiate the adapter in it. check this link
and if you want to pass data to your view holder, you should do it in the constructor, never observe for data change in view holder class.
so you can observe data in activity and pass data to your adapter.
and there is no need to call runOnUiThread
in an observer. its already on main Thread (UI Thread).
The events are dispatched on the main thread. If LiveData already has data set, it will be delivered to the observer. LiveData
Upvotes: 1