![](/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.