Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling postValue() multiple times on a Livedata will result only the last one is dispatched. Is there any alternative solution for that?

As the document says about the Livedata#postValue(T):

If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.

But I really need to call postValue() multiple times on a Livedata in a short time. I am designing a application with downloading function. I write the downloading code inside an AndroidViewmodel, and start a new Thread for each asyns downloading task. As soon as each task is completed, it postValue() to a Livedata, so there may be many tasks posting value to the same Livedata at the same time, which resulted that only the last posting works.

Is there anyway to enable me to postValue() multiple times to a Livedata at the same time and ensure all of the relative Observer react to all the posting?

------My code example is as below---------------

In the AndroidViewModel class:

private MutableLiveData<DataHolder_Task> completedTask;
    ......
        public void bulkDownload(List<DataHolder_Task> tasks){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(DataHolder_Task task:tasks)
                   {
                      //download() blocks untill task completed
                        download(task); 
                        completedTask.postValue(task);
                   }
                }
            }).start();
        }

public MutableLiveData<DataHolder_Task> getCompletedTask() {
    if(completedTask==null){
        completedTask=new MutableLiveData<>();
    }
    return completedTask;
}

In an Activity:

    androidViewModel.bulkDownload(a_list_of_tasks)
    androidViewModel.getCompletedTask().observe(this, new Observer<DataHolder_Task>() {
        @Override
        public void onChanged(DataHolder_Task task) {
            doSomething(task)
        }
    });
like image 378
vainquit Avatar asked Oct 17 '25 11:10

vainquit


2 Answers

I achieved this by subclass MutableLiveData, add a queue to buffer the bulk live datas, then dispatch one by one to the main thread:

import androidx.lifecycle.MutableLiveData
import java.util.*

class QueuedMutableLiveData<T> : MutableLiveData<T>() {
    private val queue = LinkedList<T?>()

    override fun setValue(value: T) {
        super.setValue(value)
        synchronized(queue) {
            queue.pollFirst()
            queue.peekFirst()?.run {
                super.postValue(this)
            }
        }
    }

    override fun postValue(value: T?) {
        synchronized(queue) {
            queue.add(value)
            if (queue.size == 1) {
                super.postValue(value)
            }
        }
    }
}
like image 176
VinceStyling Avatar answered Oct 20 '25 01:10

VinceStyling


You can try to use .setValue() (or .value for Kotlin) instead of .postValue(). Works for me.

like image 33
qarasique Avatar answered Oct 19 '25 23:10

qarasique



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!