【问题标题】:Android Realm Update Asynchronously Using RxJava使用 RxJava 异步更新 Android 领域
【发布时间】:2016-09-13 03:39:09
【问题描述】:

我有这个查询来更新我的领域表中已经存在的数据;

for (MyGameEntrySquad squad : response.body().getSquad()) {
            subscription = realm.where(RealmPlayer.class).equalTo("id", squad.getPlayer().getId())
                    .findFirstAsync()
                    .asObservable()
                    .subscribe(new Action1<RealmObject>() {
                        @Override
                        public void call(RealmObject realmObject) {

                        }
                    });

}

我想异步执行此查询,然后在 UI 上显示结果。

基本上,response.body().getSquad() 返回的任何内容都有一个与数据库中已有记录匹配的 id;这就是我在 equalTo 方法中使用的方法。

根据收到的数据,我想更新与 ID 匹配的每条记录上的两列。

但是,我在这方面面临一些挑战:

  1. subscribe 中的 Action1 返回的是 RealmObject 而不是 PlayerObject
  2. 如何从这里开始

我们将不胜感激。

谢谢

更新

        if (response.isSuccessful()) {
        //asynchronously update the existing players records with my squad i.e is_selected
        for (MyGameEntrySquad squad : response.body().getSquad()) {

            realm.where(RealmPlayer.class).equalTo("id", squad.getPlayer().getId())
                    .findFirstAsync()
                    .<RealmPlayer>asObservable()
                    .filter(realmPlayer -> realmPlayer.isLoaded())
                    .subscribe(player -> {
                        realm.beginTransaction();
                        if (squad.getPlayer().getPosition().equals("GK")) {
                            player.setPlaygroundPosition("gk");
                            player.setIsSelected(true);
                        }

                        // pick the flex player
                        if (squad.isFlex()) {
                            player.setPlaygroundPosition("flex");
                            player.setIsSelected(true);
                        }

                        // pick the Goalie
                        if (squad.getPlayer().getPosition().equals("GK")) {
                            player.setPlaygroundPosition("gk");
                            player.setIsSelected(true);
                        }

                        // pick the DFs
                        if ((squad.getPlayer().getPosition().equals("DF")) && (!squad.isFlex())) {
                            int dfCounter = 1;
                            player.setPlaygroundPosition(String.format(Locale.ENGLISH, "df%d", dfCounter));
                            player.setIsSelected(true);
                            dfCounter++;
                        }

                        // pick the MFs
                        if ((squad.getPlayer().getPosition().equals("MF")) && (!squad.isFlex())) {
                            int mfCounter = 1;
                            player.setPlaygroundPosition(String.format(Locale.ENGLISH, "mf%d", mfCounter));
                            player.setIsSelected(true);
                            mfCounter++;
                        }

                        // pick the FWs
                        if ((squad.getPlayer().getPosition().equals("FW")) && (!squad.isFlex())) {
                            int fwCounter = 1;
                            player.setPlaygroundPosition(String.format(Locale.ENGLISH, "mf%d", fwCounter));
                            player.setIsSelected(true);
                            fwCounter++;
                        }

                        realm.copyToRealmOrUpdate(player);
                        realm.commitTransaction();
                        updateFieldPlayers();


                    });

        }

        hideProgressBar();

    }

【问题讨论】:

  • 那么你什么时候取消订阅你的订阅者?您确实退订了,对吧?你在哪里“更新两列”?您如何显示对象(是 RecyclerView 还是其他)?这个示例代码在哪个线程上运行?目前没有足够的数据来正确回答这个问题。
  • 嗨@EpicPandaForce,我面临的部分挑战是从那时开始的,这就是为什么缺少一些信息的原因。我正在编辑原始问题以显示当前位置
  • @EpicPandaForce 是的,我取消订阅;在 onDestroy() 函数中。我现在正在使用 TableLayout
  • 为什么不用RecyclerViewGridLayoutManager
  • @EpicPandaForce 我的 UseCase 不需要 RecyclerView

标签: android asynchronous realm rx-java


【解决方案1】:
realm.where(RealmPlayer.class).equalTo("id", squad.getPlayer().getId())
                        .findFirstAsync()
                        .<RealmPlayer>asObservable()
                        .subscribe(new Action1<RealmPlayer>() {
                            @Override
                            public void call(RealmPlayer player) {

                            }
                        });

你应该这样做。

顺便说一句,循环执行是个坏主意 - 检查 RealmQuery 的 in 方法。

【讨论】:

  • 嗨@Divers,感谢您的回答。然而,我不明白最后一点。 response.body().getSquad() 的数据来自一个 HTTP 请求,用于更新现有数据
  • 不要做很多领域查询,而是获取squad.getPlayer().getId()的列表并使用in领域查询在一个查询中获取数据。如果您的问题得到了回答,请关闭它并标记答案为正确的。
【解决方案2】:
for (MyGameEntrySquad squad : response.body().getSquad()) { // btw why is this not `Observable.from()`?
        subscription = realm.where(RealmPlayer.class).equalTo("id", squad.getPlayer().getId())
                .findFirstAsync()
                .asObservable()

这不应该在 UI 线程上。它应该在后台线程上。在后台线程上,您需要使用同步查询而不是异步查询。

即使在 UI 线程上,您仍然需要 filter(RealmObject::isLoaded),因为它是一个异步查询,如果是 findFirstAsync(),您还需要过滤 RealmObject::isValid

对于这种情况,您不需要asObservable() - this method is for observing a particular item and adding a RealmChangeListener to it。考虑到这应该在具有同步查询的后台线程上,这将是不需要的(使用RealmChangeListeners 无法观察到非循环后台线程)。

您还应该在必要时取消订阅您创建的任何订阅。

是的,要在asObservable() 中获取RealmPlayer,请使用.&lt;RealmPlayer&gt;asObservable()

简而言之,您应该将该逻辑放在后台线程上,并在 UI 线程上监听变化。后台线程逻辑必须使用同步 API 完成。你不需要findFirstAsync

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-28
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多