Android 将多个Firebase回调与RxJava2相结合

Android 将多个Firebase回调与RxJava2相结合,android,firebase,kotlin,google-cloud-firestore,rx-java2,Android,Firebase,Kotlin,Google Cloud Firestore,Rx Java2,首先,这是纯粹的地狱。我从来没有经历过地狱般的痛苦。我讨厌它。总体思路是我有Firebase存储和Firestore云设置。存储器保存图像,而云保存参考存储器中图像位置的模型。然后我必须从存储器中获取图像url,以便使用它并使用glide下载。 示例:Firebase cloud为我提供了一个带有(title=“blabla”,imageUrl=“scg/asd/asd”)的drillType,然后我为我的远程存储提供了“scg/asd/asd”的imageUrl,它将其替换为我可以使用的URL

首先,这是纯粹的地狱。我从来没有经历过地狱般的痛苦。我讨厌它。总体思路是我有Firebase存储和Firestore云设置。存储器保存图像,而云保存参考存储器中图像位置的模型。然后我必须从存储器中获取图像url,以便使用它并使用glide下载。 示例:Firebase cloud为我提供了一个带有(title=“blabla”,imageUrl=“scg/asd/asd”)的drillType,然后我为我的远程存储提供了“scg/asd/asd”的imageUrl,它将其替换为我可以使用的URL。问题是回调。我不能让它按预期的方式发生。我尝试暂停函数、观察者等。其思想是,onNext应该调用getImageUrl,并使用新的Url而不是存储位置更新DrillType。但目前我无法让onNext(或.map)在继续之前等待getImageUrl的执行

存储库当前无法执行此操作

class DrillRepository(
    private val remoteDataSource: DataSource,
    private val remoteFilesDataSource: ImageUrlDataSource
) : CoroutineScope {


    private val job = Job()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.IO + job


    fun loadDrillTypes(): Observable<DrillsType> {

        return Observable.create<DrillsType> { emitter ->
            val observer = object : DisposableObserver<DrillsType>() {
                override fun onError(e: Throwable) {
                    Log.d("TAG", "error " + e.message)
                    emitter.onError(e)
                }

                override fun onNext(data: DrillsType) {
                    data.let {
                    val singleObserver = object : SingleObserver<String>{
                        override fun onSuccess(t: String) {
                            it.drillType_imageUrl = t
                            dispose()
                        }

                        override fun onSubscribe(d: Disposable) {

                        }

                        override fun onError(e: Throwable) {
                            dispose()
                        }

                    }
                        getImageUrl(it.drillType_imageUrl).subscribeWith(singleObserver)
                    }
                }

                override fun onComplete() {
                    Log.d("TAG", "COMPLETE")
                    emitter.onComplete()
                    job.cancel()
                    dispose()
                }
            }

            remoteDataSource.loadDrillTypes().subscribeWith(observer)
        }
    }

fun getImageUrl(storageLocation: String): io.reactivex.Single<String> {
        return remoteFilesDataSource.getImageUrl(storageLocation)
    }
我正在获取DrillType,但无法更新其ImageUrl。我需要等待执行,即从getImageUrl回调,然后使用更新的drillType继续onNext

编辑:这个问题我已经遇到十几次了。这是迄今为止最糟糕的一次。我正在寻找一个可能的,最好是优雅的方式,你们解决这个问题。 另外,观察家里面的观察家是绝对疯狂的,但这就是我经过多次尝试和错误后的结局

编辑2: 解决方案,希望对未来的开发人员有所帮助

    fun loadFullDrillType(): Observable<DrillsType> {
        return loadDrillTypeWithRawImageUrl().flatMapSingle { drillTypeWithRawImageUrl ->
            loadImageUrl(drillTypeWithRawImageUrl.drillType_imageUrl).map {
                return@map drillTypeWithRawImageUrl.copy(drillType_imageUrl = it)
            }
        }
    }

    fun loadDrillTypeWithRawImageUrl(): Observable<DrillsType> {
        return remoteDataSource.loadDrillTypes()
    }
fun loadFullDrillType():可观察{
返回loadDrillTypeWithRawImageUrl().flatMapSingle{drillTypeWithRawImageUrl->
loadImageUrl(drillTypeWithRawImageUrl.drillType_imageUrl).map{
return@mapdrillType WithRawImageUrl.copy(drillType\u imageUrl=it)
}
}
}
fun loadDrillTypeWithRawImageUrl():可观察{
返回remoteDataSource.loadDrillTypes()
}
返回Observable.create{emitter->
firebaseFirestore.collection(“drilltypes”)
.get()
.addOnSuccessListener{文档->
试一试{
for(文档中的文档){
val doc=document.toObject(DrillsType::class.java)
.onNext(文档)
}
}捕获(e:例外){
发射器。onError(e)
}
emitter.onComplete()
}
.addOnFailureListener{异常->
Log.w(“标记”,“获取文档时出错:”,异常)
发射器.onError(异常)
}
}
}

要充分使用RX,每个RX Firebase包装器只应执行一个操作(例如获取原始钻孔类型或仅获取图像URL)。然后使用RX构造(如map和flatMap)合并它们:

fun loadDrillTypeWithRawImageUrl(): Single<DrillsType> = TODO()
fun loadDrillImageUrl(rawImageUrl: String): Single<String> = TODO()

fun loadFullDrillType(): Single<DrillsType> {
    return loadDrillTypeWithRawImageUrl().flatMap { rawDrillsType ->
        loadDrillImageUrl(rawDrillsType.drillType_imageUrl).map { newImageUrl ->
            DrillsType(rawDrillsType.drillType_title, newImageUrl)
        }
    }
}
fun loaddrilltypewithrawmageurl():Single=TODO()
fun loadDrillImageUrl(rawImageUrl:String):Single=TODO()
fun loadFullDrillType():单个{
返回loadDrillTypeWithRawImageUrl().flatMap{rawDrillsType->
loadDrillImageUrl(rawsDrillStype.drillType_imageUrl).map{newImageUrl->
DrillsType(rawDrillsType.drillType_标题,newImageUrl)
}
}
}
data class DrillsType(
    var drillType_title: String = "",
    var drillType_imageUrl: String = ""
)
    fun loadFullDrillType(): Observable<DrillsType> {
        return loadDrillTypeWithRawImageUrl().flatMapSingle { drillTypeWithRawImageUrl ->
            loadImageUrl(drillTypeWithRawImageUrl.drillType_imageUrl).map {
                return@map drillTypeWithRawImageUrl.copy(drillType_imageUrl = it)
            }
        }
    }

    fun loadDrillTypeWithRawImageUrl(): Observable<DrillsType> {
        return remoteDataSource.loadDrillTypes()
    }
        return Observable.create<DrillsType> { emitter ->
            firebaseFirestore.collection("drilltypes")
                .get()
                .addOnSuccessListener { documents ->
                    try {
                        for (document in documents) {
                            val doc = document.toObject(DrillsType::class.java)
                            emitter.onNext(doc)
                        }
                    } catch (e: Exception) {
                        emitter.onError(e)
                    }
                    emitter.onComplete()
                }
                .addOnFailureListener { exception ->
                    Log.w("TAG", "Error getting documents: ", exception)
                    emitter.onError(exception)
                }
        }
    }
fun loadDrillTypeWithRawImageUrl(): Single<DrillsType> = TODO()
fun loadDrillImageUrl(rawImageUrl: String): Single<String> = TODO()

fun loadFullDrillType(): Single<DrillsType> {
    return loadDrillTypeWithRawImageUrl().flatMap { rawDrillsType ->
        loadDrillImageUrl(rawDrillsType.drillType_imageUrl).map { newImageUrl ->
            DrillsType(rawDrillsType.drillType_title, newImageUrl)
        }
    }
}