во-первых, это чистый ад. Мне никогда не было так тяжело, как с адом обратного вызова. Я ненавижу это. Основная идея заключается в том, что у меня есть Firebase Storage и Firestore. В хранилище хранятся изображения, в то время как в облаке хранятся модели, имеющие ссылку на расположение изображений в хранилище. Затем я должен получить URL-адрес изображения из хранилища, чтобы я мог использовать его и загрузить с помощью glide. Пример: Облако Firebase дает мне drillType с (title = "blabla", imageUrl = "scg / asd / asd"), затем я передаю своему удаленному хранилищу imageUrl из "scg / asd / asd", и оно заменяет его URL-адресом, который Я могу использовать. Проблема в обратном вызове. Я не могу заставить это произойти так, как должно. Я пытался приостановить функции, наблюдатели и так далее. Идея состоит в том, что onNext должен вызвать getImageUrl и обновить DrillType с новым URL-адресом вместо места хранения. Но в настоящее время я не могу заставить 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)
}
class FirebaseStorageDataSource(val firebaseStorage: FirebaseStorage) : ImageUrlDataSource {
override fun getImageUrl(storageLocation: String): Single<String>
{
return Single.create<String>{emitter->
firebaseStorage.getReferenceFromUrl(storageLocation).downloadUrl.addOnSuccessListener {
emitter.onSuccess(it.toString())
}.addOnFailureListener {
emitter.onError(it)
}
}
class FirebaseFirestoreDataSource(val firebaseFirestore: FirebaseFirestore) : DataSource {
override fun loadDrillTypes(): Observable<DrillsType> {
return Observable.create<DrillsType> { emitter ->
firebaseFirestore.collection("drilltypes")
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
try {
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)
}
}
}
data class DrillsType(
var drillType_title: String = "",
var drillType_imageUrl: String = ""
)
Я получаю DrillTypes, но не могу обновить их ImageUrl. Мне как-то нужно дождаться выполнения, ie обратных вызовов от getImageUrl, а затем продолжить с onNext, используя обновленный DrillType.
Редактировать: я сталкивался с этой проблемой десятки раз. Это был самый ужасный еще. Я ищу, возможно, и желательно элегантный способ, как вы, ребята, решаете эту проблему. Также наблюдатель внутри наблюдателя абсолютно сумасшедший, но именно здесь я оказался после многих проб и ошибок.
РЕДАКТИРОВАТЬ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()
}
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)
}
}
}