我有一个带有异步方法的存储库类,该异步方法返回包装在 The provided target group arn:aws:elasticloadbalancing:green/37e9e has target type ip, which is incompatible with the bridge network mode specified in the task definition. "pro-airflow-service"
中的User
:
LiveData
在ViewModel的常规作用域中,我想等待interface Repository {
fun getUser(): LiveData<User>
}
方法的结果并使用getUser()
实例。
这就是我正在寻找的东西
User
我找不到private fun process() = viewModelScope.launch {
val user = repository.getUser().await()
// do something with a user instance
}
扩展方法,以及任何实现它的尝试。
所以在做我自己之前,我想知道也许还有更好的方法吗?
我发现的所有解决方案都是将LiveData<>.await()
设为getUser()
方法,但是如果我不能更改suspend
怎么办?
答案 0 :(得分:5)
您应该能够使用await()
创建一个suspendCancellableCoroutine()
扩展功能。这可能并不完全正确,但是应该遵循以下原则:
public suspend fun <T> LiveData<T>.await(): T {
return withContext(Dispatchers.Main.immediate) {
suspendCancellableCoroutine { continuation ->
val observer = object : Observer<T> {
override fun onChanged(value: T) {
removeObserver(this)
continuation.resume(value)
}
}
observeForever(observer)
continuation.invokeOnCancellation {
removeObserver(observer)
}
}
}
}
这应该返回LiveData
发出的第一个值,而不会留下观察者。
答案 1 :(得分:0)
这是一个适合您需要的扩展功能,该功能还包括最大等待时间参数。
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS,
afterObserve: () -> Unit = {}
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
this@getOrAwaitValue.removeObserver(this)
}
}
this.observeForever(observer)
afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
this.removeObserver(observer)
throw TimeoutException("LiveData value was never set.")
}
@Suppress("UNCHECKED_CAST")
return data as T
}
答案 2 :(得分:0)
真正的Kotlin方法是更改Repository接口,并使getUser()成为暂停方法。
答案 3 :(得分:0)
suspend inline fun <T> suspendCoroutineWithTimeout(
timeout: Long,
crossinline block: (CancellableContinuation<T>) -> Unit
): T? {
var finalValue: T? = null
withTimeoutOrNull(timeout) {
finalValue = suspendCancellableCoroutine(block = block)
}
return finalValue
}
suspend inline fun <T> suspendCoroutineObserverWithTimeout(
timeout: Long,
data: LiveData<T>,
crossinline block: (T) -> Boolean
): T? {
return suspendCoroutineWithTimeout<T>(timeout) { suspend ->
var observers : Observer<T>? = null
val oldData = data.value
observers = Observer<T> { t ->
if (oldData == t) {
KLog.e("参数一样,直接return")
return@Observer
}
KLog.e("参数不一样,刷新一波")
if (block(t) && !suspend.isCancelled) {
suspend.resume(t)
observers?.let { data.removeObserver(it) }
}
}
data.observeForever(observers)
suspend.invokeOnCancellation {
KLog.e("删除observiers")
observers.let { data.removeObserver(it) }
}
}
}