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
库上。
在我删除它并注释掉所有使用它的代码后,它开始工作了。
我正在尝试使用 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
库上。
在我删除它并注释掉所有使用它的代码后,它开始工作了。