使用 SQLBrite + Retrofit 刷新数据 [英] Refreshing data using SQLBrite + Retrofit

查看:56
本文介绍了使用 SQLBrite + Retrofit 刷新数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的用例:

我正在开发一个应用程序,该应用程序通过 REST API 与服务器通信,并将接收到的数据存储在 SQLite 数据库中(它将其用作某种缓存).

I am developing an app that communicates with a server via a REST API and stores the received data in a SQLite database (it's using it as a cache of some sorts).

当用户打开屏幕时,必须发生以下情况:

When the user opens a screen, the following has to occur:

  1. 数据从数据库加载(如果有).
  2. 应用调用 API 来刷新数据.
  3. API 调用的结果会保存到数据库中.
  4. 当数据更改通知被拦截时,数据从数据库重新加载.

这与提交的案例非常相似 此处,但略有不同.

This is very similar to the case presented here, but there is a slight difference.

由于我使用的是 SQLBrite,DB observables 不会终止(因为在那里注册了一个 ContentObserver,它将新数据推送到流中),所以像 concatmerge 等将不起作用.

Since I am using SQLBrite, the DB observables don't terminate (because there is a ContentObserver registered there, that pushes new data down the stream), so methods like concat, merge, etc. won't work.

目前,我已经使用以下方法解决了这个问题:

Currently, I have resolved this using the following approach:

Observable.create(subscriber -> {
    dbObservable.subscribe(subscriber);
    apiObservable
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe(
            (data) -> {
                try {
                    persistData(data);
                } catch (Throwable t) {
                    Exceptions.throwOrReport(t, subscriber);
                }
            },

            (throwable) -> {
                Exceptions.throwOrReport(throwable, subscriber);
            })
})

看起来它工作正常,但它看起来并不优雅和正确".

It seems like it's working OK, but it just doesn't seem elegant and "correct".

您能否建议或指出一个资源来解释处理这种情况的最佳方法是什么?

Can you suggest or point me to a resource that explains what's the best way to handle this situation?

推荐答案

如果您稍微改变一下思维方式,问题的解决方案实际上非常简单和干净.我使用的是完全相同的数据交互(Retrofit + Sqlbrite),这个解决方案非常有效.

The solution to your problem is actually super easy and clean if you change the way of thinking a bit. I am using the exact same data interaction (Retrofit + Sqlbrite) and this solution works perfectly.

您需要做的是使用两个独立的可观察订阅,它们处理完全不同的过程.

What you have to do is to use two separate observable subscriptions, that take care of completely different processes.

  1. Database -> View:这个用来附加你的View(ActivityFragment 或任何显示您的数据)到 db 中的持久数据.您为创建的 View 订阅一次.
  1. Database -> View: This one is used to attach your View (Activity, Fragment or whatever displays your data) to the persisted data in db. You subscribe to it ONCE for created View.

dbObservable
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(data -> {
            displayData(data);
        }, throwable -> {
            handleError(throwable);
        });

  1. API -> Database:另一个是从 api 获取数据并将其持久化到数据库中.每次您想刷新数据库中的数据时,您都会订阅它.
  1. API -> Database: The other one to fetch the data from api and persist it in the db. You subscribe to it every time you want to refresh your data in the database.

apiObservable
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe(data -> {
           storeDataInDatabase(data);
        }, throwable -> {
            handleError(throwable);
        });

<小时>

您不想将两个 observables 都转换"为一个,纯粹是因为您在问题中包含的原因.两个 observable 的行为完全不同.

You don't want to "transform" both observables into one, purely for the reason you've included in your question. Both observables act completely differently.

来自 Retrofit 的 observable 就像一个 单个.它做它需要做的事情,并完成(使用 onCompleted).

The observable from Retrofit acts like a Single. It does what it needs to do, and finishes (with onCompleted).

Sqlbrite 中的 observable 是一个典型的 Observable,它会在每次特定表更改时发出一些信息.理论上应该在未来完成.

The observable from Sqlbrite is a typical Observable, it will emit something every time a specific table changes. Theoretically it should finish in the future.

Ofc 你可以解决这个差异,但它会让你远离干净且易于阅读的代码.

Ofc you can work around that difference, but it would lead you far, far away from having a clean and easily readable code.

如果你真的、真的需要公开一个 observable,你可以隐藏这样一个事实,即在订阅你的数据库.

If you really, really need to expose a single observable, you can just hide the fact that you're actually subscribing to the observable from retrofit when subscribing to your database.

  1. 将 Api 订阅包装在一个方法中:

public void fetchRemoteData() {
    apiObservable
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.io())
            .subscribe(data -> {
                persistData(data);
            }, throwable -> {
                handleError(throwable);
            });
}

  1. fetchRemoteData 订阅

dbObservable
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .doOnSubscribe(() -> fetchRemoteData())
        .subscribe(data -> {
            displayData(data);
        }, throwable -> {
            handleError(throwable);
        });

我建议你认真考虑一下.因为你强迫自己进入需要单个可观察对象的位置这一事实可能会严重限制你.我相信这正是会迫使你在未来改变你的观念的事情,而不是保护你免受改变本身的影响.

I suggest you really think about all that. Because the fact that you're forcing yourself into the position where you need a single observable, might be restricting you quite badly. I believe that this will be the exact thing that will force you to change your concept in the future, instead of protecting you from the change itself.

这篇关于使用 SQLBrite + Retrofit 刷新数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆