我应该如何在嵌套代码中 return "Observable/Flowable/Single" "onError" ?

How should I return "Observable/Flowable/Single" "onError" in nested code?

我正在使用 "RxJava"、"Room"、"Firebase (Firestore)" 和 "Kotlin" 开发一个 Android 应用程序。 它基于 MVP 模式。

我是 RxJava 的新手,所以我需要帮助... 对我来说很难...

场景是... 1. Presenter 向 DAO 请求用户(本地数据库 - 房间) 2. DAO return 是一个用户 2.1 如果用户不存在,Presenter向Firebase(Firestore)请求用户 3. 演示者 return 要查看的用户。

代码在这里:

[1]道

@Dao
interface PlayersDao {
    @Query("SELECT * FROM player WHERE playerName = :playerName")
    fun getPlayerByName(playerName: String): Single<Player>
}

[2] Firebase

class FirebaseDataSource {
    private val mFirestore = FirebaseFirestore.getInstance()

    override fun getPlayerByName(playerName: String) = Single.create<Player> { emitter ->
        mFirestore.collection(PLAYERS)
            .whereEqualTo("playerName", playerName)
            .get()
            .addOnCompleteListener {
                if (it.isSuccessful && !it.result.isEmpty) {
                    emitter.onSuccess(it.result.documents[0].toObject(Player::class.java))
                } else {
                    emitter.onError(PlayerNotExistException())
                }
            }
    }
}

[3] 主持人

fun getPlayer(playerName: String): Single<Player> {
    return Single.create { emitter ->
        playerDao.getPlayerByName(playerName)
            .doOnError {
                // When it failed to get the user from local, it should retry to Firebase.
                // But I don't know how should I cover this logic.
                Single.create<Player> { emitter2 ->
                    firebaseDataSource.getPlayerByName(playerName)
                        .doOnError {
                            Log.d(TAG, "getPlayerByName(firebase) - failed")
                        }
                        .doOnSuccess {
                            emitter.onSuccess(it)
                        }
                    }
                }
                .doOnSuccess {
                    Log.d(TAG, "getPlayerByName(local) - success")
                    emitter.onSuccess(it)
                }
    }
}

当无法从本地数据库获取用户时,我不知道应该如何获取和return用户。

和"Single"是正确的吗? 我应该使用 "Observable" 还是 "Flowable"?

<<<------------------------ 这由 Ahmed Ashraf G 清除。

这是一个连续的问题。 我修复了如下代码:

主持人

fun getPlayer(playerName: String): Single<Player> {
    Log.d(TAG, "getPlayerByName - $playerName")

    return playerDao.getPlayerByName(playerName)
            .onErrorResumeNext {
                Log.d(TAG, "[BS] getPlayerByName(local) - onError: ${it.message}")
                playersFirebaseDataSource.getPlayerByName(playerName)
                    .doOnSuccess {
                        Log.d(TAG, "getPlayerByName(firebase) - success")
                        playerDao.savePlayer(it) // Here is run in "Main" thread
                    }.subscribeOn(Schedulers.io())
            }
}

playerDao.savePlayer(it)

这段代码应该在后台线程中。 但事实并非如此。 我应该怎么解决它?

您正在寻找 "onErrorResumeNext" 运算符。 来自文档:

onErrorResumeNext( ) — instructs an Observable to emit a sequence of items if it encounters an error.

所以它可能看起来像这样:

return playerDao.getPlayerByName(playerName)
         .onErrorResumeNext(firebaseDataSource.getPlayerByName(playerName))

这个基本上是尝试DAO单,遇到错误就切换到FirebaseDataSource单。

编辑:您可以在 Here

中找到其他错误处理运算符

编辑 2:至于你的第二个问题,你使用 observeOn 是正确的,它将在特定调度程序上切换工作,但你也使用了 subscribeOn 这可能是有害的,在这里这就是为什么 subscribeOn 只能使用一次,它指定您将 "observe" 可观察对象所在的线程,它通常与 AndroidSchedulers.mainThread().[=18= 一起使用]

我建议通过 Here

阅读有关该主题的更多信息

为了解决连续题,我自己修改了代码

fun getPlayer(playerName: String): Single<Player> {
    return playerDao.getPlayerByName(playerName)
        .onErrorResumeNext {
            Log.d(TAG, "getPlayerByName(local) - onError: ${it.message}")
            playersFirebaseDataSource.getPlayerByName(playerName)
                .subscribeOn(Schedulers.io()) // I added this two line
                .observeOn(Schedulers.io())   // And it works fine.
                .doOnSuccess {
                    Log.d(TAG, "getPlayerByName(firebase) - success")
                    playerDao.savePlayer(it) // Now, here is run in the background thread!
                }.subscribeOn(Schedulers.io())
        }
}