![](/img/trans.png)
[英]how to call a function every several millisecond using coroutine in kotlin
[英]How to call Kotlin coroutine in composable function callbacks?
我想在可组合函数的回调中调用一个挂起函数。
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是实验性的。
我不能在getLocationOnClick
使用launchInComposition
因为launchInComposition
是@Composable
而getLocationOnClick
不能是@Composable
。
在@Composable
函数中,在常规函数中获得挂起函数结果的最佳方法是什么?
创建一个与可组合的生命周期相关联的协同作用域,并使用该作用域调用您的挂起函数
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")
}
}
您可以使用 ViewModel 的 viewModelScope 或任何其他协程范围。
从 LazyColumnFor 中删除项目的操作示例,该操作需要由 ViewModel 处理的挂起调用。
class ItemsViewModel : ViewModel() {
private val _itemList = MutableLiveData<List<Any>>()
val itemList: LiveData<List<Any>>
get() = _itemList
fun deleteItem(item: Any) {
viewModelScope.launch(Dispatchers.IO) {
TODO("Fill Coroutine Scope with your suspend call")
}
}
}
@Composable
fun Example() {
val itemsVM: ItemsViewModel = viewModel()
val list: State<List<Any>?> = itemsVM.itemList.observeAsState()
list.value.let { it: List<Any>? ->
if (it != null) {
LazyColumnFor(items = it) { item: Any ->
ListItem(
item = item,
onDeleteSelf = {
itemsVM.deleteItem(item)
}
)
}
} // else EmptyDialog()
}
}
@Composable
private fun ListItem(item: Any, onDeleteSelf: () -> Unit) {
Row {
Text(item.toString())
IconButton(
onClick = onDeleteSelf,
icon = { Icons.Filled.Delete }
)
}
}
这对我有用:
@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")
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.