使用 SQLBrite + Retrofit 刷新数据

2024-01-09

这是我的用例:

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

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

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

这与所呈现的案例非常相似here http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/,但有细微差别。

由于我使用的是 SQLBrite,DB 可观察量不会终止(因为有一个ContentObserver在那里注册,将新数据推送到流中),因此像这样的方法concat, merge等将不起作用。

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

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

看起来它工作正常,但它看起来并不优雅和“正确”。

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


如果你稍微改变一下思维方式,你的问题的解决方案实际上是非常简单和干净的。我正在使用完全相同的数据交互(Retrofit + Sqlbrite),并且该解决方案完美运行。

您所要做的就是使用两个单独的可观察订阅,它们负责完全不同的流程。

  1. Database -> View: 这个是用来附加你的View (Activity, Fragment或任何显示您的数据的内容)到数据库中的持久数据。您订阅一次即可创建View.
dbObservable
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(data -> {
            displayData(data);
        }, throwable -> {
            handleError(throwable);
        });
  1. API -> Database:另一种是从 api 获取数据并将其保存在数据库中。每次您想要刷新数据库中的数据时,您都需要订阅它。
apiObservable
        .subscribeOn(Schedulers.io())
        .observeOn(Schedulers.io())
        .subscribe(data -> {
           storeDataInDatabase(data);
        }, throwable -> {
            handleError(throwable);
        });

EDIT:

您不想将两个可观察量“转换”为一个,纯粹是因为您在问题中包含的原因。两个可观察量的行为完全不同。

The observable来自 Retrofit 的作用就像Single http://reactivex.io/RxJava/javadoc/rx/Single.html。它做了它需要做的事情,并完成(与onCompleted).

The observableSqlbrite 是一个典型的Observable,每次特定表发生变化时它都会发出一些东西。理论上应该会在未来完成。

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

如果你真的真的需要暴露一个observable,你可以只hide事实上,当订阅数据库时,您实际上是在订阅来自改造的可观察数据。

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 SQLBrite + Retrofit 刷新数据 的相关文章

  • Google Map Android API v2 无法在 Play 商店应用程序中显示地图

    我正在与Google Map Android API v2在 Android 应用程序中 它可以很好地与未签名的应用程序在不同的设备上 但是 当我签署 apk 并将应用程序上传到 Play 商店时 下载的应用程序显示白屏而不是地图 您使用什
  • 我可以为 Android Activity 分配“默认”OnClickListener() 吗?

    我有一个 Activity 对于布局中的每个小部件 我调用 setOnClickListener 来分配我的 OnClick 处理程序 在我的 OnClick 处理程序中 我使用 switch 语句根据 View 参数的 ID 为每个按钮执
  • Android Activity 重新创建自身

    我的应用程序通常运行得很好 直到我在特定设备上遇到奇怪的问题 App中有2个活动 当我在 ActivityA 内启动 ActivityB 后 ActivityA 启动时没有问题 但是 当我通过按下硬件按钮或调用 finish 返回 Acti
  • Android Wear - 在没有 WearableListenerService 的情况下从 Wear 接收消息?

    我正在开发一款适用于 Android Wear 的应用程序 它可以在手机上启动活动 一切都很好 但我不想依赖手机上不断运行的后台服务来接收此消息 理想情况下 我会让 WearableListenerService 与应用程序同时启动 并保持
  • Android 堆栈大小

    我如何获取和更改 Android 应用程序的堆栈大小 即使是主线程 主线程堆栈大小是在固件中设置的 无法修改 除非修改您自己手机的固件 正如斯特朗先生指出的那样 对于您分叉的线程 您可以设置自己的堆栈大小
  • 相机预览的有效模糊

    到目前为止我尝试过的 将每一帧转换为位图 然后用library https github com wasabeef Blurry并将其放入ImageView这是在相机预览前 显然太慢了 就像1 fps 然后我开始使用渲染脚本这会模糊每一帧
  • Android布局中如何实现Button的自动宽度

    我有几个垂直列出的按钮 我需要它们都具有相同的宽度 而且还要显示其中的所有文本 基本上我需要所有它们的宽度作为最大的宽度的包裹宽度 希望我解释得很好 现在 我已经有一种布局可以在我的 Samsung Galaxy S2 4 1 2 上运行
  • 显示葡萄牙语字符 Android

    我正在开发一个 Android 应用程序 当它应该写 n o 或 cabe a 等单词 例如带有 或 的字符 时 它会写 或 我已经检查过源文件编码 它是UTF 8 看起来 UTF8 被解释为 ISO 8859 x 理论上 你可以提供 ja
  • Android studio 模拟器中运行的WebView无法访问互联网,但Chrome可以?

    我安装了 Android studio 1 0 1 并按照此页面操作https developer chrome com multidevice webview gettingstarted https developer chrome c
  • 重置首选项的默认值

    我正在使用 CheckBoxPreference 作为设置屏幕 XML 是
  • 如何使用android ndk r9b为Android编译FFMPEG

    我想设计一个Android应用程序 可以通过FFMPEG命令播放和编辑视频 但我不知道如何在Android上使用FFMPEG 我尝试过从Google搜索到的许多方法 但它们太旧了 无法实现 现在 FFMPEG的最新版本是2 1 1 Andr
  • Buildozer Numpy RuntimeError:工具链损坏:无法链接简单的 C 程序

    用 Python 编写我的第一个 Android 应用程序并使用 Buildozer 对其进行打包 因为稍后在项目中需要使用numpy 所以我尝试打包以下测试代码 import numpy import kivy kivy require
  • Android 改造参数化@Headers

    我正在使用 OAuth 每次发出请求时都需要将 OAuth 令牌放入标头中 我看到 Header注释 但是有没有办法让它参数化 以便我可以在运行时传入 这是概念 Header Authorization OAuth var api vers
  • 改变换行行为

    我可以在 TextView 中使用 Spannable 创建具有不同外观 下划线 删除线等的跨度 我怎样才能做同样的事情来改变换行行为 特别是 我不希望电子邮件地址在中间换行 我希望它像一个单词一样 I tried 包裹在一起跨度 http
  • android中ScrollView中的图像

    在我的应用程序中 我想放置一个 png 文件 并且希望它在横向和纵向模式下都被视为滚动图像 请建议代码或示例 要使您的 Imageview 在高度不适合时滚动 您可以在 xml 中的 ScrollView 内添加一个 ImageView 并
  • 上传失败您应该使用 http 和 https 作为您的 Web 意图过滤器的方案

    上传失败 您应该使用 http 和 https 作为您的 Web 意图过滤器的方案 我在将免安装应用上传到 Play 商店时收到此错误 我在清单中声明了 http 和 https 的意图过滤器 如下所示
  • 膨胀类 android.support.design.internal.BottomNavigationView 时出错

    我正在制作我的第一个应用程序 这是一个简单的应用程序 带有启动屏幕和主要活动 现在我有两个构建变体 免费版本 活动底部有 Admob 横幅 付费版本 该应用程序不会在底部显示 admob 横幅 而是将其替换为用于切换活动的底部导航视图 我将
  • 没有 Google Play 服务的设备的后备计划是什么

    目前 我正在将以前使用 jar 库的 Google 服务迁移到 Google Play 服务 谷歌广告移动 谷歌分析 谷歌云端硬盘 然而 在迁移指南中 Google 没有提到对于没有 Google Play 服务或没有最新的 Google
  • OnSwipe 方法在 RecyclerView 中不起作用

    我正在开发一个用于播放音频文件的应用程序 创建了包含 2 个选项卡的选项卡布局 两者中都使用了片段RecyclerView两者都被使用 该片段名为LibraryFragment有这个RecycleView其物品在刷卡时必须传递给HomeFr
  • 无法查询 ContentResolver 以从 my_downloads 获取下载文件的名称,但在 all_downloads 中工作正常

    我的应用程序设置为激活一次具有扩展名的文件 myappdata被打开 它通过这个意图过滤器来实现这一点

随机推荐

  • RMongo dbGetQueryForKeys 返回 NA

    我正在使用dbGetQueryForKeys函数 我在这里了解到 https stackoverflow com questions 14486780 rmongo dbgetqueryforkeys what is the structu
  • 如何将 BGL 有向图用作无向图(用于布局算法)?

    我正在使用 Boost Graph 制作有向图 实际上是双向图 我想使用现有的布局算法 Kamada Kawai 或 Fruchterman Reingold 但它们只接受无向图作为参数 使用这些布局算法的最简单方法是什么 更一般地说 引诱
  • 当我停止 putty 时,如何在 ubuntu 14.04 上运行 jar 文件而不停止?

    我使用的是ubuntu 14 04 我正在运行一个 jar 文件 该文件应该在几天内收集大量数据 我正在运行 jar 文件 认为这个命令运行良好 java jar xxx jar 但是 当我关闭腻子时 该过程停止了 有没有办法让 jar 文
  • 在 Scala 中将 DataFrame 转换为 RDD[Map]

    我想转换创建的数组 如下所示 case class Student name String age Int val dataFrame DataFrame sql createDataFrame sql sparkContext paral
  • PostgreSQL 的 NGINX TLS 终止

    我一直在尝试使用 NGINX 作为 PostgreSQL 数据库的 TLS 终结器 但没有成功 当我尝试连接到数据库时 出现以下错误 服务器意外关闭连接 这可能意味着服务器在处理请求之前或处理过程中异常终止 当我删除ssl选项中listen
  • 无法让 mongoose-unique-validator 工作

    这不可能那么困难 但我总是收到默认的 mongoose 11000 错误 这是我的代码的简化版本 model import mongoose from mongoose import uniqueValidator from mongoos
  • 将 BlackBerry 应用程序设计得像 iPhone

    我正在将应用程序从 iPhone 移植到 BlackBerry BlackBerry 应用程序往往看起来不像 iPhone 那样精美 但自然地 我希望尽可能保持精美 而不破坏任何重要的 UI 约定 有没有任何 UI 组件可以帮助解决这个问题
  • 带图像的自定义标题

    我正在通过禁用标准标题并自己管理所有内容来为活动创建自定义标题 我想知道是否可以根据我的需要替换 主题标准标题 我可以通过更改 windowXYZStyle 项目来通过主题自定义大小 背景图像和文本 我唯一找不到的东西 如何添加图像而不是文
  • 设置 Qt QPushButton 弹出菜单的位置(向右)

    我正在为 Qt 按钮小部件编写弹出菜单 每当单击按钮时 就会弹出一个菜单 在按钮下方 默认情况下 弹出菜单位于下方左侧 有没有办法让弹出菜单在按钮下方的右侧弹出 没有设置位置的功能 所以我想知道是否有一些复杂的方法可以做到这一点 这是一些代
  • 在 Flask 的 url_for 函数中禁用字符转义

    Flask 有吗url for方法有一个选项可以禁用自动转义吗 所以如果我有一个名为getUser像这样的路线 user
  • pandas read_sql 在列名中删除点

    这是一个错误还是我做错了什么 我创建一个 df 将其放入 sql 表中 df 和表有一列 其中有一个点 现在 当我从 sql 表中读取 df 时 列名不一样 我编写了这段小代码 以便人们可以测试它 import sqlalchemy imp
  • 如何在不配置的情况下更改 npm 前缀?

    我不小心将 npm 前缀更改为不存在的地方 是否有一个我可以访问的配置文件可以让我将其更改回来 我能想到的唯一选择是 完全卸载节点 更改前缀后 npm 没有响应 https stackoverflow com questions 39250
  • H264 中的 Elementary Stream 是什么意思

    我读了 Elementary Stream 的内容维基百科 http en wikipedia org wiki Elementary stream 我正在使用的工具 Live555 需要 H 264 视频基本流文件 因此 当从视频应用程序
  • 在Java中仅获取路径目录并丢弃文件

    我们如何实际丢弃 java 字符串中的最后一个文件并仅获取文件路径目录 用户输入的随机路径 C my folder tree apple exe 期望的输出 C my folder tree 我找到的最接近的解决方案来自here https
  • Dockerfile 中 VOLUME 的用途是什么

    我试图更深入地了解 Docker 的体积 但我很难找出以下方面的差异 用例 The docker volume create command The docker run v path host path The VOLUME条目在Dock
  • 移动 N 天活跃用户 (BigQuery)

    我有一个由两列组成的 事件 表 userId eventDate s234124 2015 01 01 a2s3166 2015 01 02 c216782 2015 01 03 z312235 2015 01 04 userId 是用户
  • 如何将“ON更新当前时间戳”添加到现有表列

    我有一个列 例如 ts activity 其数据类型为 MYSQL 时间戳 默认值为当前时间戳 我想添加更新应用当前时间戳到该列值 我无法通过更改查询来执行此操作 在创建新表及其列时 我可以添加该列 但无法通过添加更新应用当前时间戳来修改现
  • 将 ExpressionEngine 成员导出到 WordPress

    我需要将所有成员从 ExpressionEngine 站点导出到 WordPress 我该怎么办呢 将它们全部移动 包括所有密码等 似乎是一项艰巨的任务 关于如何开始有什么想法吗 如果是这种情况 用户在登录新的 WordPress 站点时必
  • 为什么pip从10版本升级到18版本?

    运行时pip install脚本我收到以下警告 You are using pip version 10 0 1 however version 18 0 is available 这很奇怪 pip项目刚刚从版本10升级到版本18吗 为什么
  • 使用 SQLBrite + Retrofit 刷新数据

    这是我的用例 我正在开发一个应用程序 它通过 REST API 与服务器通信 并将接收到的数据存储在 SQLite 数据库中 它将其用作某种缓存 当用户打开屏幕时 必须发生以下情况 数据从数据库加载 如果可用 应用程序调用API刷新数据 A