首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Retrofit、RxJava2和Room的类型一致性:如果响应是数组或对象,如何使用相同的有效负载反序列化JSON,但使用不同的“根键”

Retrofit、RxJava2和Room的类型一致性:如果响应是数组或对象,如何使用相同的有效负载反序列化JSON,但使用不同的“根键”
EN

Stack Overflow用户
提问于 2019-02-18 00:43:23
回答 1查看 86关注 0票数 0

由于RxJava2使用的JSON键命名约定,我正在努力在我的Kotlin应用程序中跨Retrofit、Room和API保持一致的类型。我试图研究解决以下问题的最好方法,但我想不出更好的方法来解决它,我对社区提供的东西很感兴趣。

考虑下面的例子;

我在Android上使用Kotlin语言,并使用Retrofit和GSON执行网络请求。根据响应是Array还是单个Object,我使用的API为JSON提供了不同的根密钥名。

每个Object的有效负载是相同的,但如果响应是Array,则根密钥是复数。

例如,假设我有一个为用户定义的数据类:

代码语言:javascript
运行
复制
data class User(var id: Int?, name: String?)

如果我向单个用户发出API请求,该API将返回以下内容:

代码语言:javascript
运行
复制
{
  "user": {
    "id": 1,
    "name: "Sam"
  }
}

如果我向多个用户发出API请求,该API将返回以下内容:

代码语言:javascript
运行
复制
{
  "users": [{
    "id": 1,
    "name: "Sam"
  }]
}

有效负载是相同的,但根密钥在userusers之间变化。我已经创建了一个数据类来处理单独的根键:

代码语言:javascript
运行
复制
data class Users(
        @SerializedName("users") var users: List<User>?,
        @SerializedName("user") var user: User?
)

当发出单独的API请求时,我对两者都使用Users数据类:

代码语言:javascript
运行
复制
/** GET single user by ID */
@GET("users/{id}")
    fun getUser(
        @Path("id") id: Int?): Single<Users>

/** GET list of users */
@GET("users")
    fun getUsers(): Single<Users>

当我将响应保存到Room数据库时,我分别使用response.usersresponse.user访问它。设置房间以返回UserList<User>形式的查询,这在RxJava2流中使用Retrofit请求时会产生问题。例如,如果房间数据库返回Maybe<List<User>>,则这是一个非常简单的流

代码语言:javascript
运行
复制
usersRepository.getAll()
    .switchIfEmpty(api.getUsers())

usersRepository.getAll()的结果是List<User>,但是如果来自数据库的结果是空的,并且我尝试回退到API请求,RxJava2将显示Incompatible Type错误,因为api.getUsers()请求返回类型Single<Users>而不是Single<List<User>>。如果API请求能够使用相同的类型,我就不会有问题,但是我不能在Retrofit请求上指定Single<List<User>>,因为GSON不能正确地反序列化响应。

正因为如此,根据我目前对这个问题的理解(这可能是外行的,我很愿意被塑造),我正在分离数据库和API请求,并做了大量的empty/null检查,这阻止了我将所有东西都保存在一个漂亮而整洁的RxJava2流中。

我希望这个问题足够清楚,我重视每个人的意见。谢谢您抽时间见我!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-19 10:17:59

这是一个非常常见的问题,人们喜欢做的是创建一个包装器类来处理转换、验证和所有其他痛苦的工作,并使用该类来执行网络请求,而不是直接调用改进的api。

例如,考虑像这样创建一个类:

代码语言:javascript
运行
复制
class UserClient {

    private val userApi: UserApi

    fun getUser(id: Int): Single<User> {
        return userApi.getUser(id) // This has a type of Single<Users>
            .map { it.user } // now it's map to Single<User>
    }

    fun getUsers(): Single<List<User>> {
        return userApi.getUsers() // This has a type of Single<Users>
            .doOnSuccess { Log.d(TAG, "yay!")}
            .doOnError { e -> Log.d(TAG, "Something went wrong: $e")}
            .map { it.users } // Now it's map to Single<List<User>>
    }
}

然后你可以这样做:

代码语言:javascript
运行
复制
usersRepository.getAll()
    .switchIfEmpty(UserClient.getInstance().getUsers())
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54735344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档