Android 我该如何返回;“可观察/可流动/单一”&引用;onError";在嵌套代码中?

Android 我该如何返回;“可观察/可流动/单一”&引用;onError";在嵌套代码中?,android,firebase,kotlin,rx-java,android-room,Android,Firebase,Kotlin,Rx Java,Android Room,我正在使用“RxJava”、“Room”、“Firebase(Firestore)”和“Kotlin”开发一个Android应用程序。 它基于MVP模式 我是RxJava的新手,所以我需要帮助。。。 这对我来说很难 情况是。。。 1.演示者向DAO请求用户(本地数据库室) 2.DAO返回一个用户 2.1如果用户不存在,演示者将向Firebase(Firestore)请求用户 3.演示者返回要查看的用户 代码如下: [1] 刀 @Dao interface PlayersDao { @Qu

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

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

情况是。。。 1.演示者向DAO请求用户(本地数据库室) 2.DAO返回一个用户 2.1如果用户不存在,演示者将向Firebase(Firestore)请求用户 3.演示者返回要查看的用户

代码如下:

[1] 刀

@Dao
interface PlayersDao {
    @Query("SELECT * FROM player WHERE playerName = :playerName")
    fun getPlayerByName(playerName: String): Single<Player>
}
@Dao
接口PlayersDao{
@查询(“从playerName=:playerName的播放器中选择*)
趣味getPlayerByName(playerName:String):单曲
}
[2] 火基

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())
                }
            }
    }
}
类FirebaseDataSource{
private val mFirestore=FirebaseFirestore.getInstance()
覆盖有趣的getPlayerByName(playerName:String)=Single.create{emitter->
mFirestore.collection(播放器)
.whereEqualTo(“playerName”,playerName)
.get()
.addOnCompleteListener{
if(it.issusccessful&&!it.result.isEmpty){
emitter.onSuccess(it.result.documents[0].toObject(Player::class.java))
}否则{
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)
                }
    }
}
fun getPlayer(playerName:String):单人{
返回Single.create{emitter->
playerDao.getPlayerByName(playerName)
杜恩先生{
//当无法从本地获取用户时,应重试Firebase。
//但我不知道我该怎么解释这个逻辑。
Single.create{emitter2->
firebaseDataSource.getPlayerByName(playerName)
杜恩先生{
Log.d(标记“getPlayerByName(firebase)-失败”)
}
杜恩塞斯先生{
发射器。onSuccess(it)
}
}
}
杜恩塞斯先生{
Log.d(标记“getPlayerByName(本地)-成功”)
发射器。onSuccess(it)
}
}
}
我不知道当从本地数据库获取用户失败时,应该如何获取并返回用户

“单身”是正确的吗? 我应该使用“可观察”还是“可流动”

你在找“下一个”接线员。 从文档中:

下一个( ) — 指示可观察对象在遇到错误时发出一系列项

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

return playerDao.getPlayerByName(playerName)
         .onErrorResumeNext(firebaseDataSource.getPlayerByName(playerName))
这基本上是尝试DAO单,如果遇到错误,它将切换到FirebaseDataSource单

编辑:您可以在中找到其他错误处理运算符

编辑2:至于第二个问题,您可以使用
observeOn
切换特定计划程序上的工作,但您也使用了可能有害的
subscribeOn
,这就是为什么
subscribeOn
只能使用一次,它指定了“观察”的线程可观察的,它通常与
AndroidSchedulers.mainThread()
一起使用


我建议通过

阅读更多关于这个主题的内容。为了解决这个连续的问题,我自己修改了代码

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())
        }
}
fun getPlayer(playerName:String):单人{
return playerDao.getPlayerByName(playerName)
.下一个{
Log.d(标记“getPlayerByName(本地)-onError:${it.message}”)
playerFireBaseDataSource.getPlayerByName(playerName)
.subscribeOn(Schedulers.io())//我添加了这两行
.observeOn(Schedulers.io())//并且工作正常。
杜恩塞斯先生{
Log.d(标记“getPlayerByName(firebase)-成功”)
playerDao.savePlayer(it)//现在,这里是在后台线程中运行的!
}.subscribeOn(Schedulers.io())
}
}

Ahmed Ashraf G,我修正了它,我还有一个问题。你能回答我吗?@yoonhok是的,当然我在这里添加了额外的问题,你能检查一下吗?你自己想得很好:)我编辑了我的答案,希望它能帮上忙。真的谢谢你:)你的评论对我很有帮助。
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())
        }
}