【问题标题】:How to call suspend function in Activity?如何在Activity中调用挂起函数?
【发布时间】:2021-11-24 00:45:51
【问题描述】:

我正在做一个项目,我想从 Api 获取数据并将其显示在 UI 中。顺便说一句,我正在使用 Jetpack Compose。如何在 Main Activity 中调用挂起函数?我想获取列表,然后在LotrAppTheme{} 中调用函数bookListScreen(bookList : BookList)。我该怎么做?

主要活动:

package com.example.lotrapp
 
    @AndroidEntryPoint
    class MainActivity : ComponentActivity() {
    
        private val bookViewModel: BookViewModel by viewModels()
        private lateinit var bookList : BookList
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            setContent {
                LOTRAppTheme {
    
                }
            }
    
        }
    }
    
    @Preview(showBackground = true)
    @Composable
    fun DefaultPreview() {
        LOTRAppTheme {
    
        }
    }

查看模型:

package com.example.lotrapp

import androidx.lifecycle.ViewModel
import com.example.lotrapp.models.BookList
import com.example.lotrapp.repository.BookRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class BookViewModel @Inject constructor(
    private val repository: BookRepository
) : ViewModel() {

    suspend fun getBookList() : BookList? {
        return repository.getBookList()
    }
}

BookListScreen

@Composable
fun bookListScreen(bookList : BookList) {

    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Gray)
    ) {

        LazyColumn(
            contentPadding = PaddingValues(all = 12.dp),
            verticalArrangement = Arrangement.spacedBy(12.dp)
        ) {
            itemsIndexed(
                items = bookList.docs
            ) {
                index, book -> BookItem(book)
            }
        }


    }
}

【问题讨论】:

  • Activity 中执行业务逻辑是一种不好的做法。您可以在视图模型中调用一个方法,该方法又调用挂起函数
  • 嗨。你先是接受了我的回答,然后又推翻了你的决定。让它工作有问题吗?
  • 其实是的,当我按照你说的做的时候,列表是空的。 idk 有什么问题,但我们不需要在那里的某个地方添加一个“记住”吗?而且它是一个异步函数,我们如何确保它在可组合函数(bookListScreen)运行之前完成?

标签: kotlin retrofit2 kotlin-coroutines android-jetpack-compose dagger-hilt


【解决方案1】:

您可以在使用init 创建视图模型后立即获取图书列表,并将结果值存储在可变状态持有者中:通过使用可变状态,您可以确保您的视图会在新值出现时更新。

在 compose documentation 中查看有关状态的更多信息,包括解释基本原则的 this youtube video

@HiltViewModel
class BookViewModel @Inject constructor(
    private val repository: BookRepository
) : ViewModel() {

    var bookList by mutableStateOf<BookList?>(null)

    init {
        viewModelScope.launch {
            bookList = getBookList()
        }
    }

    private suspend fun getBookList() : BookList? {
        return repository.getBookList()
    }
}

然后你可以根据状态显示需要的视图:

val bookList = viewModel.bookList
if (bookList != null) {
    BookListScreen(bookList)
} else {
    // loading
}

【讨论】:

    【解决方案2】:

    正如@gtxtreme 所说,业务逻辑不能在活动中,但如果您在活动中做某事需要您在可组合中启动协程,那么您可以使用以下方式创建协程范围:

    val coroutineScope = rememberCoroutineScope()
    

    然后,只要您想使用暂停功能:

    coroutineScope.launch {
      //do some suspend work
      }
    

    或者,如果您希望有一个协程范围来经常根据特定键(例如本地数据库中的搜索查询)运行您的 api,那么在 compose 中使用所谓的 Handlers示例:

    LaunchedEffect(key1 = searchQuery){
                //do api call
      }
    

    闭包之间的代码将在第一次组合时以及代码更改时运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-13
      • 2021-12-21
      • 2022-01-18
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      相关资源
      最近更新 更多