我应该如何在嵌套代码中 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())
}
}
我正在使用 "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())
}
}