LiveData不会为每个列表项更新,只为最后一个更新



我有一个字符串LiveData,它是从我自己的一个方法生成的标识符。我的问题是,我在recyclerview中有一个列表,当倒计时计时器结束时,recycleriew的所有项目都必须生成一个标识符,但它只生成列表中最后一个项目的标识符。

这就是我尝试的:

var userPhone = 0
private fun setUpObservable() {
myViewModel.apply {
identifierAction.observe() {response - >
if(response is IdentifierAction.Identifier)
handleIdentifier(response.identifier)
}
}
}
private fun handleIdentifier(identifier: String) {
//list using data class with name(String), lastname(String), phone(Int) and identifier(String)
var myList = MySharedPreference.getMyList(context)
val itemToOverride = myList.find {
it.phone == userPhone
}
if (itemToOverride != null) {
MySharedPreference.removeUser(context, itemToOverride)
itemToOverride.identifier = identifier
MySharedPreference.addUser(context, itemToOverride)
myList = MySharedPreference.getMyList(context)
myAdapter.setList(myList)
}
}
override fun onFinish(position: Int) {
//list using data class with name(String), lastname(String), phone(Int) and identifier(String)
val myList = MySharedPreference.getMyList(context)
if (position != 1) {
userPhone = myList[position].phone
myViewModel.generateIdentifier(IdentifierRequisites(name = myList[position].name, lastname = myList[position].lastname, phone = myList[position].phone))
}
}

适配器:

class MyAdapter(private var list: MutableList <MyUser> = mutableListOf(),private var listener: OnTimerFinishListener) {
interface OnTimerFinishListener {
fun onFinish(position: Int)
}
private fun startCountDownTimer(myList: MyUser) {
var timer = object: CountDownTimer(15000, 1000) {
override fun onTick(left: Long) {
//do something every second
}
private fun setList(myList: List <MyUser> ) {
this.list = myList.sortedBy {
it.name
}.toMutableList()
notifyDataSetChanged()
}
override fun onFinish() {
listener.onFinish(absoluteAdapterPosition)
}
}
}
}

ViewModel:

private val _identifierAction: MutableLiveData < IdentifierAction > by lazy {
MutableLiveData < IdentifierAction > ().apply {
value = IdentifierAction.Init
}
}
val identifierAction: LiveData < IdentifierAction > get() = _identifierAction
fun generateIdentifier(data: IdentifierRequisites) {
viewModelScope.launch {
val response = generateIdentifierUseCase.invoke(data)
_identifierAction.postValue(IdentifierAction.Identifier(response))
}
}

计时器结束时,会为列表中的每个项目调用onFinish方法,但只有最后一个项目会触发handleIdentifier方法。我该如何解决这个问题?如何等待每个项目都获得标识符?

它们可能生成得很好,只是LiveData的值更新得很快,当它向观察者推送新值时,它已经被设置为列表中的最后一个ID。像这样:

class CoolVM : ViewModel() {
val someLiveData = MutableLiveData<Int>()
fun setData(number: Int) {
viewModelScope.launch {
Log.i("ViewModel", "Updating with number: $number")
someLiveData.postValue(number)
}
}
}
class MainFragment : Fragment(R.layout.fragment_main) {
private val model: CoolVM by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.someLiveData.observe(viewLifecycleOwner) { num ->
Log.i("Observer", "Observer got number: $num")
}
(1..5).forEach(model::setData)
}
}

日志输出为

Updating with number: 1
Updating with number: 2
Updating with number: 3
Updating with number: 4
Updating with number: 5
Observer got number: 5

这就是LiveData的工作方式,我不知道有什么方法可以强制它立即推送每个更新。它的重点更多地放在当前值上,它主要是作为一种以被动方式驱动UI的方式。由于UI只需要更新每一帧,因此当有一系列快速连续的更新时,它不需要处理每个中间值。


我不是协程专家,所以也许其他人可以提供更好的解决方案,但你可以尝试使用Channel(就像一个队列(和collect,将值流作为Flow:

class CoolVM : ViewModel() {
val numbers = Channel<Int>()

fun setData(number: Int) {
viewModelScope.launch {
Log.i("ViewModel", "Updating with number: $number")
numbers.send(number)
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
model.numbers.consumeAsFlow().collect { num ->
Log.i("Observer", "Observer got number: $num")
}
}
}
(1..5).forEach(model::setData)
}

哪个立即处理每个值,进而

Updating with number: 1
Observer got number: 1
Updating with number: 2
Observer got number: 2
Updating with number: 3
Observer got number: 3
Updating with number: 4
Observer got number: 4
Updating with number: 5
Observer got number: 5

我不能100%确定这是否是正确的方法,或者是否有什么需要注意的问题,如果有人知道得更好,请告诉我!

最新更新