后台线程或非UI组件中的LiveData

时间:2019-01-23 13:24:51

标签: android mvvm android-livedata

亲爱的。我曾经使用MVP模式开发Android应用程序,现在尝试将MVVM与诸如DataBind和LiveData的体系结构组件一起使用。

我编写了提供LiveData的Repository类:

LiveData<MyEntity> getById(long id);

对于活动/片段,我观察到ViewModel(使用我的存储库)公开的LiveData,并且一切正常。

问题是我必须安排一个警报来显示带有与MyEntity相关的文本的通知,因此我创建了一个包含MyEntityId作为Extra的Intent。

当AlarmManager调用我的BroadcastReceiver时,我需要使用存储库来获取MyEntity。关键是如何在非UI组件中“观察” LiveData。

此外,我可以启动IntentService(后台线程)以避免访问主线程中的存储库,并使用RxJava中的“ blockingNext”之类的东西,但是我仍然找不到等待LiveData的方法。

这样做的正确方法是什么?请注意,由于遗留问题,我的存储库可能无法使用Room实施。

谢谢

到目前为止,我唯一想到的解决方案是在存储库中使用以下方法:

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

但这对我来说并不好。 所以我想问一下实现此方法的正确方法。

最好的问候

2 个答案:

答案 0 :(得分:0)

您只能在UI组件(例如活动/片段)中观察liveData。

对于您的方案,您可以创建一个在非UI类中也可以观察到的观察者类,或者可以使用EventBus。

了解观察者:https://developer.android.com/reference/java/util/Observer

关于EventBus:https://github.com/greenrobot/EventBus

答案 1 :(得分:0)

最好避免这种情况,但是如果您确实需要它并且真的知道自己在做什么,则可以尝试以下代码:

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];
}