William Miranda
William Miranda

Reputation: 303

LiveData in Background Threads or non-UI components

Dears. I used to develop Android apps using MVP pattern and now I'm trying the MVVM with Architecture components like DataBind and LiveData.

I wrote my Repository class that provides a LiveData:

LiveData<MyEntity> getById(long id);

For Activity/Fragments I observe the LiveData exposed by ViewModel (that uses my Repository) and everything works fine.

The problem is I have to schedule an Alarm to display a Notification with a text related to MyEntity, so I created an Intent containing my MyEntityId as an Extra.

When the AlarmManager calls my BroadcastReceiver, I need to use the Repository to get MyEntity. The point is how to "Observe" the LiveData inside a non-UI component.

Also, I can start an IntentService (background thread) to avoid accessing the Repository in the Main Thread, and use something like "blockingNext" from RxJava, but I still could not figure a way to wait for LiveData.

What is the correct way of doing this? Note that my Repository may not be implemented using Room, due to legacy issues.

Thanks

The only solution I figured so far was have methods like this in the Repository:

LiveData<MyEntity> getByIdLive(long id);
MyEntity getById(long id);

But this does not look good for me. So I'd like to ask how is the correct way of implement this.

Best Regards

Upvotes: 6

Views: 5661

Answers (2)

algrid
algrid

Reputation: 5954

It's better to avoid such things, but if you really need it and really know what you're doing you can try the following code:

public static <T> void observeOnce(final LiveData<T> liveData, final Observer<T> observer) {
    liveData.observeForever(new Observer<T>() {
        @Override
        public void onChanged(T t) {
            liveData.removeObserver(this);
            observer.onChanged(t);
        }
    });
}

@WorkerThread
public static <T> T waitSync(final LiveData<T> liveData) {
    final Object lock = new Object();
    final Object[] result = new Object[1];
    final boolean[] resultReady = new boolean[] {false};
    (new Handler(Looper.getMainLooper())).post(new Runnable() {
        @Override
        public void run() {
            observeOnce(liveData, new Observer<T>() {
                @Override
                public void onChanged(T t) {
                    synchronized (lock) {
                        result[0] = t;
                        resultReady[0] = true;
                        lock.notify();
                    }
                }
            });
        }
    });
    synchronized (lock) {
        try {
            while (!resultReady[0]) {
                lock.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        }
    }
    return (T) result[0];
}

Upvotes: 1

mudassar raza
mudassar raza

Reputation: 119

You can only observe liveData in UI components like Activity/Fragment.

For your scenario, you can create an observer class which can be observed in non-UI classes as well or you can use EventBus.

to read about observer: https://developer.android.com/reference/java/util/Observer

about EventBus: https://github.com/greenrobot/EventBus

Upvotes: 0

Related Questions