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

Viewed 1339

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)
        }
    });
3 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)
            }
        }
    }
}

LiveData is designed as a life-cycle aware observable object that informs a UI of the latest state. It is not an event stream.

Is there any alternative solution for that?

Try a Kotlin Flow.

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

Related