kotlin 主线程在协程中获取数据以避免空值的最佳解决方案是什么?

jvidinwx  于 2023-02-09  发布在  Kotlin
关注(0)|答案(2)|浏览(160)

我有下面的代码,在click事件中,我需要使用从数据库中查询的类。

data class Work(...)

fun Compose(){
    var work1: Work? = null
    var work2: Work? = null
    var work3: Work? = null

    LaunchedEffect(true){
        CoroutineScope(IO).launch {
            work1 = workViewModel.getById(1)
            work2 = workViewModel.getById(2)
            work3 = workViewModel.getById(3)
        }
    }

    Card(
        modifier = Modifier
        .clickable(onClick = {
            val url = "https://www.google.com/"
                                
            when{
                url.contains(work1?.baseUrl) -> {...}
                url.contains(work2?.baseUrl) -> {...}
                url.contains(work3?.baseUrl) -> {...}
            }
        })       
    ){}

}

这产生了一个问题,work3?.baseUrl发现String?type需要CharSequence类型。
到目前为止,似乎只有!!操作符可以成功运行此代码。但此代码是基于数据库查询的,使用!!操作符是非常危险的。
如果在此之前添加一个空操作符,也不会起作用。

requireNotNull(work1)  

    when{
        url.contains(work1.baseUrl) -> {...}
    }

无法智能强制转换为“Work”,因为“work1”是由更改闭包捕获的局部变量
你能告诉我最好的解决办法是什么吗?

xwbd5t1u

xwbd5t1u1#

我建议不要在Composable中使用这种逻辑,而尝试将其移到ViewModel中的函数中,类似于:

private val url = "https://www.google.com/"

fun validateBaseUrl() {
  viewModelScope.launch(Dispatchers.IO) {
            workViewModel.getById(1)?.let {
               if (url.contains(it)) { .. }
            }
            work2 = workViewModel.getById(2)?.let {
               if (url.contains(it)) { .. }
            }
            work3 = workViewModel.getById(3)?.let {
               if (url.contains(it)) { .. }
            }
  }

}

然后在可组合的部分中会是这样的:

fun Compose() {
   Card(
        modifier = Modifier
        .clickable(onClick = { viewModel.validateBaseUrl() })       
    ){}
}

记住使用状态提升,而不是通过可组合对象发送视图模型。
最后,您需要使用LiveData或StateFlow将State发送回Composable。

ddarikpa

ddarikpa2#

您需要为work属性创建一个作用域:

work1?.run { url.contains(baseUrl) } == true -> {...}

run lambda中,即使工作属性本身是可变的,被访问的对象也是不可变的。需要== true是因为比较操作符的左边可以是布尔值或空值。
您还可以像这样定义扩展函数:

fun Work?.isContainedIn(url: String) = this?.run { url.contains(baseUrl) } == true

然后就这么做

work1.isContainedIn(url) -> { }
work2.isContainedIn(url) -> { }
work3.isContainedIn(url) -> { }

相关问题