![](/img/trans.png)
[英]How to handle 204 response in Retrofit using Kotlin Coroutines?
[英]how to handle callback using kotlin coroutines
以下代碼段在順序代碼流中將結果返回為“null”。 我知道協程可能是異步處理回調的可行解決方案。
fun getUserProperty(path: String): String? {
var result: String? = null
database.child(KEY_USERS).child(getUid()).child(path)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
Log.e(TAG, "error: $error")
}
override fun onDataChange(snapshot: DataSnapshot) {
Log.w(TAG, "value: ${snapshot.value}")
result = snapshot.value.toString()
}
})
return result
}
在這種情況下,協程是否可以幫助等待回調的結果(onDataChange()/onCancelled())?
由於 Firebase 實時數據庫 SDK 不提供任何掛起功能,因此協程在處理其 API 時沒有幫助。 您需要將回調轉換為掛起函數,以便您能夠在協程中等待結果。
這是一個執行此操作的掛起擴展功能(我通過谷歌搜索 發現了一個解決方案):
suspend fun DatabaseReference.getValue(): DataSnapshot {
return async(CommonPool) {
suspendCoroutine<DataSnapshot> { continuation ->
addListenerForSingleValueEvent(FValueEventListener(
onDataChange = { continuation.resume(it) },
onError = { continuation.resumeWithException(it.toException()) }
))
}
}.await()
}
class FValueEventListener(val onDataChange: (DataSnapshot) -> Unit, val onError: (DatabaseError) -> Unit) : ValueEventListener {
override fun onDataChange(data: DataSnapshot) = onDataChange.invoke(data)
override fun onCancelled(error: DatabaseError) = onError.invoke(error)
}
有了這個,您現在可以在協程中等待 DatabaseReference 上的getValue()
可疑方法。
singleValueEvent 的 @Doug示例如果您想繼續列出您可以使用如下協程流程:
@ExperimentalCoroutinesApi
inline fun <reified T> DatabaseReference.listen(): Flow<DataResult<T?>> =
callbackFlow {
val valueListener = object : ValueEventListener {
override fun onCancelled(databaseError: DatabaseError) {
close(databaseError.toException())
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
try {
val value = dataSnapshot.getValue(T::class.java)
offer(DataResult.Success(value))
} catch (exp: Exception) {
Timber.e(exp)
if (!isClosedForSend) offer(DataResult.Error(exp))
}
}
}
addValueEventListener(valueListener)
awaitClose { removeEventListener(valueListener) }
}
如果有人仍然使用原始答案的代碼但需要更新它以匹配Coroutines
的非實驗版本,我是這樣更改它的:
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.ValueEventListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
suspend fun DatabaseReference.getSnapshotValue(): DataSnapshot {
return withContext(Dispatchers.IO) {
suspendCoroutine<DataSnapshot> { continuation ->
addListenerForSingleValueEvent(FValueEventListener(
onDataChange = { continuation.resume(it) },
onError = { continuation.resumeWithException(it.toException()) }
))
}
}
}
class FValueEventListener(val onDataChange: (DataSnapshot) -> Unit, val onError: (DatabaseError) -> Unit) : ValueEventListener {
override fun onDataChange(data: DataSnapshot) = onDataChange.invoke(data)
override fun onCancelled(error: DatabaseError) = onError.invoke(error)
}
然后使用它就像: val snapshot = ref.getSnapshotValue()
更新
我還需要觀察一個節點並使用 Omar 的答案來做到這一點。 如果有人需要一個如何在此處使用它的示例,它是:
@ExperimentalCoroutinesApi
inline fun <reified T> DatabaseReference.listen(): Flow<T?>? =
callbackFlow {
val valueListener = object : ValueEventListener {
override fun onCancelled(databaseError: DatabaseError) {
close()
}
override fun onDataChange(dataSnapshot: DataSnapshot) {
try {
val value = dataSnapshot.getValue(T::class.java)
offer(value)
} catch (exp: Exception) {
if (!isClosedForSend) offer(null)
}
}
}
addValueEventListener(valueListener)
awaitClose { removeEventListener(valueListener) }
}
然后在 Activity 或 Fragment 中調用它,您可以像這樣創建您的偵聽器:
var listener = FirebaseUtils.databaseReference
.child(AppConstants.FIREBASE_PATH_EMPLOYEES)
.child(AuthUtils.retrieveUID()!!).listen<User>()
然后在你的函數中調用它:
CoroutineScope(IO).launch {
withContext(IO) {
listener?.collect{
print(it)
}
}
}
然后在onStop()
內部處理:
override fun onStop(){
listener = null
super.onStop()
}
@狗的答案是正確的,但很難理解。 這是有關如何將回調轉換為協程的說明https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#6
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.