我想在composable-function的回调中调用暂停功能。
suspend fun getLocation(): Location? { /* ... */ }
@Composable
fun F() {
val (location, setLocation) = remember { mutableStateOf<Location?>(null) }
val getLocationOnClick: () -> Unit = {
/* setLocation __MAGIC__ getLocation */
}
Button(onClick = getLocationOnClick) {
Text("detectLocation")
}
}
如果我会使用Rx,那么我可以subscribe
。
我可以先做invokeOnCompletion
,然后再做getCompleted
,但该API是试验性的。
我不能在launchInComposition
中使用getLocationOnClick
,因为launchInComposition
是@Composable
,而getLocationOnClick
不能是@Composable
。
在@Composable
函数内部的常规函数中获取悬挂函数结果的最佳方法是什么?
答案 0 :(得分:7)
创建与可组合对象生命周期相关联的协程范围,并使用该范围调用您的暂停函数
suspend fun getLocation(): Location? { /* ... */ }
@Composable
fun F() {
// Returns a scope that's cancelled when F is removed from composition
val coroutineScope = rememberCoroutineScope()
val (location, setLocation) = remember { mutableStateOf<Location?>(null) }
val getLocationOnClick: () -> Unit = {
coroutineScope.launch {
val location = getLocation()
}
}
Button(onClick = getLocationOnClick) {
Text("detectLocation")
}
}
答案 1 :(得分:2)
您可以使用ViewModel的viewModelScope或任何其他协程范围。
从LazyColumnFor中删除项目的操作示例,该操作需要由ViewModel处理的暂停调用。
spark-shell
答案 2 :(得分:0)
这对我有用:
@Composable
fun TheComposable() {
val coroutineScope = rememberCoroutineScope()
val (loadResult, setLoadResult) = remember { mutableStateOf<String?>(null) }
IconButton(
onClick = {
someState.startProgress("Draft Loading...")
coroutineScope.launch {
withContext(Dispatchers.IO) {
try {
loadResult = DataAPI.getData() // <-- non-suspend blocking method
} catch (e: Exception) {
// handle exception
} finally {
someState.endProgress()
}
}
}
}
) {
Icon(Icons.TwoTone.Call, contentDescription = "Load")
}
我还尝试了以下辅助函数,以强制开发同事处理异常并最终清理状态(也使相同的代码(也许!?)更短一些,(也许!?)更具可读性):
fun launchHelper(coroutineScope: CoroutineScope,
catchBlock: (Exception) -> Unit,
finallyBlock: () -> Unit,
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
return coroutineScope.launch(context, start) {
withContext(Dispatchers.IO) {
try {
block()
} catch (e: Exception) {
catchBlock(e)
} finally {
finallyBlock()
}
}
}
}
这里是如何使用该辅助方法:
@Composable
fun TheComposable() {
val coroutineScope = rememberCoroutineScope()
val (loadResult, setLoadResult) = remember { mutableStateOf<String?>(null) }
IconButton(
onClick = {
someState.startProgress("Draft Loading...")
launchHelper(coroutineScope,
catchBlock = { e -> myExceptionHandling(e) },
finallyBlock = { someState.endProgress() }
) {
loadResult = DataAPI.getData() // <-- non-suspend blocking method
}
}
) {
Icon(Icons.TwoTone.Call, contentDescription = "Load")
}
}