【问题标题】:Realm transaction in RxJava onNext freezes appRxJava onNext 中的领域事务冻结应用程序
【发布时间】:2016-07-24 13:57:37
【问题描述】:

设置

我使用 Retrofit 从 REST API 检索数据。我使用 RxJava 的 Observable,而不是 Retrofit 通常的响应。在onNext(Object obj) 回调方法中,我告诉视图在地图上为我通过API 收到的每个项目显示标记。此外,我想将每个条目保存到 Realm 数据库中。

问题

保存到数据库有效。但是,它会阻塞 UI 很长一段时间,有时会导致多达 1000 个跳过帧。如果没有领域部分,显示所有标记——尽管一次超过 3000 个(出于性能和可用性的原因,我将它们聚集在一起)只需要几分之一秒。但是,有了它,应用程序似乎冻结了几秒钟。

不过,保存到数据库是可行的——Realm 会填充所有条目。但是速度太慢了。

实施

(在将代码粘贴到此处之前,我做了一些重命名并缩短了代码,以显示我认为可能存在问题的部分。)

MapsPresenter.java

class MapsPresenter implements Presenter<MapsView> {

    private MapsView mapsView;

    private Subscription subscription;

    private MyApiClient apiClient;
    private Realm realm;

    MapsPresenter() {
        apiClient = MyApp.getMyApiClient();
        realm = RealmController.with(MyApp.getInstance()).getRealm();
    }


    void loadRetailers(...) {
        if (subscription != null && !subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }

        mapsView.showProgressIndicator();

        subscription = apiClient.retailers()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io())
            .flatMap(new Func1<Retailers, Observable<Retailer>>() {
                @Override
                public Observable<Dealer> call(Retailers retailers) {
                    return Observable.from(retailers.retailerList);
                }
            })
            .subscribe(new Subscriber<Dealer>() {
                @Override
                public void onCompleted() {
                    ...
                }

                @Override
                public void onError(Throwable e) {
                    ...
                }

                @Override
                public void onNext(Retailer retailer) {
                    realm.beginTransaction();
                    realm.insertOrUpdate(retailer);
                    realm.commitTransaction();
                }
            });
        }
    }
}

RealmController.java

public class RealmController {

    private static RealmController instance;
    private final Realm realm;

    public RealmController(Application application) {
        realm = Realm.getDefaultInstance();
    }

    public static RealmController with(Application application) {

        if (instance == null) {
            instance = new RealmController(application);
        }
        return instance;
    }

    public static RealmController getInstance() {

        return instance;
    }

    public Realm getRealm() {

        return realm;
    }

    ...
}

问题

如何提高插入/更新领域条目的速度,即使在 API 调用之后有几百个操作?有什么我忽略的吗?

【问题讨论】:

  • 我不知道为什么(Rx 让我很困惑),但是您的写入是在 UI 线程上,并且您正在逐个而不是批量保存每个元素。
  • @EpicPandaForce 将写入转移到 I/O 线程并仅将整个 List 提供给 Realm 确实改进了一些事情。谢谢!
  • 我也遇到过类似的问题,请查看stackoverflow.com/a/55195053/2462531 我是如何修复的。

标签: android performance realm rx-java


【解决方案1】:

首先,非常喜欢你提出问题的方式。

  1. 您的 flatMap 代码应该在您的 subscribeOn 之上,以使其在 observeOn 中给出的调度程序上运行。现在该代码正在 MainThread 上运行。

  2. 您正在 MainThread 上执行 Realm 写操作,这很好,但您没有使用 Realm 提供的 Aync 方法,请尝试在 executeTransactionAsync 块中执行写操作。

  3. 这与您面临的问题无关,但可以改进您在 Presenter 中处理订阅的方式。

示例如下所示,

public void fetchGitHubUsersFromRetrofit() {
  internetConnection.isInternetOn(context)
    .filter(connectionStatus -> connectionStatus)
    .switchMap(connectionStatus -> gitHubApiInterface.getGitHubUsersList())
    .subscribeOn(rxSchedulerConfiguration.getComputationThread())
    .observeOn(rxSchedulerConfiguration.getMainThread())
    .map(gitHubUserList -> {
      realm.executeTransactionAsync(realm -> realm.copyToRealmOrUpdate(gitHubUserList));
    });
}

如果您正在寻找详细的代码参考,请查看此https://github.com/viraj49/Realm_android-injection-rx-test

【讨论】:

  • RxJava 和 Realm 对我来说还是很新的——我在一个项目中使用它们来学习如何使用这些库等等。依赖注入和 Lambda 在我的列表中。最后发现我什至不再需要 flatMap 操作了。所以你的提示加上 EpicPandaForce 的评论帮助了我。我会调查你名单上的第 3 项。谢谢!
猜你喜欢
  • 2020-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多