当视图模型中的另一个 LiveData 更新时,触发更新 LiveData 成员。

6
在一个文字游戏应用中,我在活动和片段之间共享一个模型:
public class MainViewModel extends AndroidViewModel {
    private LiveData<List<Game>> mGames;
    private final MutableLiveData<Game> mDisplayedGame = new MutableLiveData<>();

(请原谅截图中的非英文文本)

activity and fragment

该活动观察用户当前正在玩的mGames,并更新导航抽屉菜单(请参见上面截图的左侧)。
该片段观察mDisplayedGame并在自定义视图中显示它(请参见上面截图的右侧)。
我的问题是,当游戏列表在服务器上更新时(并且活动通过Websocket接收到新的游戏列表并将其存储在Room中),我需要向片段发布更新:“嘿,你正在显示的游戏已更新,请重新绘制它!”
是否可以从共享视图模型内部执行此操作?
我知道我也可以在片段中观察mGames并添加一个代码,遍历它们,然后找出服务器上是否更新了显示的游戏。
但我更喜欢在MainViewModel中执行此操作,因为我有一种感觉,即片段应仅观察它正在显示的一个游戏,而仅此而已。
简而言之,每当通过Room在视图模型中更新mGames时,我也需要通知mDisplayedGame观察者!

2
看一下 MediatorLiveData(还有一些 Transformation 方法可能也可以胜任……其中一些我认为只是包装了 MediatorLiveData)。 - John O'Reilly
Transformations.switchMap 应该可以工作。 - EpicPandaForce
2个回答

4
你应该使用MediatorLiveData来实现这个功能。
它的工作方式是这样的:
public class MainViewModel extends AndroidViewModel {
    private final LiveData<List<Game>> mGames;
    private final MutableLiveData<Game> mSelectedGame = new MutableLiveData<>();

    private final MediatorLiveData<Game> mDisplayedGame = new MediatorLiveData<>();

    {
        mDisplayedGame.addSource(mGames, (data) -> {
            // find the new value of the selected game in the list
            mSelectedGame.setValue(newSelectedGame);
        });

        mDisplayedGame.addSource(mSelectedGame, (data) -> {
            mDisplayedGame.setValue(data);
        });
    }

然后你将 mDisplayedGame 暴露为一个 LiveData<Game>,就可以工作了。


谢谢,MediatorLiveData现在对我有效了。你有什么想法,如何将MediatorLiveData与Room调用结合起来,这是否可能?如果我从“addSource”中调用DAO方法,我应该将它们包装在“Executors.newSingleThreadScheduledExecutor().execute(...)”中吗? - Alexander Farber
1
不确定为什么我之前没有回答这个问题,但是是的,您确实希望将DB查询移动到后台线程。您可以使用postValue来从中返回。请注意,您可能已经启动了一个查询,然后收到了新的事件发射,在这种情况下,您可能希望忽略先前启动查询的结果。 - EpicPandaForce
你想将执行器作为字段引用保留,而不是每次创建一个。 - EpicPandaForce

-3

使用回调 - 在您的ViewModel中添加一个回调接口和一个setCallback方法 - 让您的Fragment实现它,然后调用viewmodel.setCallback(fragment) - 在您的Observer中调用回调


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接