Nyc*_*cta 8 android kotlin kotlin-coroutines android-jetpack-compose
我想在可组合函数的回调中调用一个挂起函数。
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")
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 Rx,那么我可以只使用subscribe.
我可以做invokeOnCompletion然后getCompleted,但那个 API 是实验性的。
我不能使用launchInCompositioningetLocationOnClick因为launchInCompositionis@Composable和getLocationOnClickcan not be @Composable。
在常规函数内部获得挂起函数结果的最佳方法是@Composable什么?
hey*_*hey 18
创建一个与可组合的生命周期相关联的协同作用域,并使用该作用域调用您的挂起函数
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")
}
}
Run Code Online (Sandbox Code Playgroud)
Dir*_*ann 11
这对我有用:
@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")
}
Run Code Online (Sandbox Code Playgroud)
我还尝试了以下辅助函数,以强制开发同事处理异常并最终清理状态(也使相同的代码(也许!?)更短并且(也许!?)更具可读性):
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()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
以下是如何使用该辅助方法:
@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")
}
}
Run Code Online (Sandbox Code Playgroud)
您可以使用 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 }
)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4232 次 |
| 最近记录: |