如何将 Compose LazyColumn 与 Coroutines/Room 数据库一起使用?
How do you use Compose LazyColumn with Coroutines/Room Database?
我正在为自己编写一个简单的应用程序,以将 RSS 提要显示为项目列表,并认为这是了解 @Compose lazyColumn
的好机会。我对它的代码如此之少感到震惊,没有 Adapter,没有 ViewHolder,没有 xml。惊人的流线型。
但是您如何设置它以使用 Room Database
之类的东西,您正在使用协程从数据库中提取数据?官方文档 here 谈到了 rememberCoroutineScope()
但没有解释你在哪里定义它。在 Surface 定义中放置协程感觉很奇怪,这可能就是它不起作用的原因。它会产生一个:@Composable invocations can only happen from the context of a @Composable function
错误。
这需要通过 ViewModel
完成吗?在现实世界中,存储库中的数据无论如何都来自 ViewModel
,但现在我只想显示一个简单的从互联网上提取的项目列表(即,需要协程)。但是你如何处理来自 ViewModel/Database 的 LiveData
或 List<String>
?
有人知道如何设置吗?我觉得应该不难,但我不知道从哪里开始寻找答案。
例如:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
val composeScope = rememberCoroutineScope()
Surface(color = MaterialTheme.colors.background) {
composeScope.launch{ // do network call
RssList(RssFetcher.fetchRss()) // how do you make this work?
}
}
}
}
}
}
@Composable
fun RssList(list: List<RssItems>){
LazyColumn{ items(list) ... }
}
@Composable
fun TestView(
) {
var rssList by remember { mutableStateOf(emptyList<RssItems>()) }
LaunchedEffect(Unit) {
rssList = RssFetcher.fetchRss()
}
RssList(rssList)
}
@Composable
fun RssList(list: List<RssItems>){
LazyColumn{ items(list) ... }
}
要了解这里发生的事情,您需要查看以下内容:
- 在撰写中存储状态。
remember { mutableStateOf() }
是在重组之间存储数据的最简单方法。但是当你在视图之间切换时它会被清理,所以也检查视图模型,这可能更适合你的任务。 documentation
- LaunchedEffect 是在可组合函数内执行任何操作的首选方式。在此块中,您已经在协程中,运行
suspend
函数 也可以
- 你不需要为
rememberCoroutineScope
定义协程,它returns预初始化协程。通常你需要将它用于按钮按下或触摸等事件
创建视图模型,理想情况下,假设您可能希望保留下载的供稿以供将来使用。
class RSSViewModel : ViewModel() {
var RSS by mutableStateOf(listOf</*Add Type Here*/>()) // could be val as well
private set // No external modifications to protect from side-effects
init {
viewModelScope.launch { // Pre-defined Coroutine Scope
RSS =
RSSFetcher.fetchRSS() // You could also extract the logic into a method for on-demand initialisation
}
}
fun refreshRSS() { // This is what I was talking about above. On-demand
viewModelScope.launch {
RSS =
RSSFetcher.fetchRSS()
}
}
}
现在,注意我们已经声明了 MutableState<T>
类型的变量,这在 Compose 中是触发重组所必需的(您也可以使用 LiveData
或 Flow
,但我强烈建议使用尽你所能,提供高可靠性)。
好了,我们都设置到这里了,现在只需将代码添加到 activity
class MainActivity : ComponentActivity() {
private val viewModel by viewModels<RSSViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
RSSList(viewModel.RSS) // Automatic Recompositions on Refresh, all done!
}
}
}
}
是的,
编辑:如果你想从房间数据库中提取提要,如果你return原样的原始数据,那将是一团糟。 Exceptions
会说你不能在主线程上调用它;然后在整个地方添加那些 thread(){...}
电话,这使它看起来比你的房间更乱。为此,改为 return LiveData
。令人惊讶的是,如果你return LiveData
从数据库查询,你实际上可以调用主线程上的方法。清洁。
我正在为自己编写一个简单的应用程序,以将 RSS 提要显示为项目列表,并认为这是了解 @Compose lazyColumn
的好机会。我对它的代码如此之少感到震惊,没有 Adapter,没有 ViewHolder,没有 xml。惊人的流线型。
但是您如何设置它以使用 Room Database
之类的东西,您正在使用协程从数据库中提取数据?官方文档 here 谈到了 rememberCoroutineScope()
但没有解释你在哪里定义它。在 Surface 定义中放置协程感觉很奇怪,这可能就是它不起作用的原因。它会产生一个:@Composable invocations can only happen from the context of a @Composable function
错误。
这需要通过 ViewModel
完成吗?在现实世界中,存储库中的数据无论如何都来自 ViewModel
,但现在我只想显示一个简单的从互联网上提取的项目列表(即,需要协程)。但是你如何处理来自 ViewModel/Database 的 LiveData
或 List<String>
?
有人知道如何设置吗?我觉得应该不难,但我不知道从哪里开始寻找答案。
例如:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
val composeScope = rememberCoroutineScope()
Surface(color = MaterialTheme.colors.background) {
composeScope.launch{ // do network call
RssList(RssFetcher.fetchRss()) // how do you make this work?
}
}
}
}
}
}
@Composable
fun RssList(list: List<RssItems>){
LazyColumn{ items(list) ... }
}
@Composable
fun TestView(
) {
var rssList by remember { mutableStateOf(emptyList<RssItems>()) }
LaunchedEffect(Unit) {
rssList = RssFetcher.fetchRss()
}
RssList(rssList)
}
@Composable
fun RssList(list: List<RssItems>){
LazyColumn{ items(list) ... }
}
要了解这里发生的事情,您需要查看以下内容:
- 在撰写中存储状态。
remember { mutableStateOf() }
是在重组之间存储数据的最简单方法。但是当你在视图之间切换时它会被清理,所以也检查视图模型,这可能更适合你的任务。 documentation - LaunchedEffect 是在可组合函数内执行任何操作的首选方式。在此块中,您已经在协程中,运行
suspend
函数 也可以
- 你不需要为
rememberCoroutineScope
定义协程,它returns预初始化协程。通常你需要将它用于按钮按下或触摸等事件
创建视图模型,理想情况下,假设您可能希望保留下载的供稿以供将来使用。
class RSSViewModel : ViewModel() {
var RSS by mutableStateOf(listOf</*Add Type Here*/>()) // could be val as well
private set // No external modifications to protect from side-effects
init {
viewModelScope.launch { // Pre-defined Coroutine Scope
RSS =
RSSFetcher.fetchRSS() // You could also extract the logic into a method for on-demand initialisation
}
}
fun refreshRSS() { // This is what I was talking about above. On-demand
viewModelScope.launch {
RSS =
RSSFetcher.fetchRSS()
}
}
}
现在,注意我们已经声明了 MutableState<T>
类型的变量,这在 Compose 中是触发重组所必需的(您也可以使用 LiveData
或 Flow
,但我强烈建议使用尽你所能,提供高可靠性)。
好了,我们都设置到这里了,现在只需将代码添加到 activity
class MainActivity : ComponentActivity() {
private val viewModel by viewModels<RSSViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
RSSList(viewModel.RSS) // Automatic Recompositions on Refresh, all done!
}
}
}
}
是的,
编辑:如果你想从房间数据库中提取提要,如果你return原样的原始数据,那将是一团糟。 Exceptions
会说你不能在主线程上调用它;然后在整个地方添加那些 thread(){...}
电话,这使它看起来比你的房间更乱。为此,改为 return LiveData
。令人惊讶的是,如果你return LiveData
从数据库查询,你实际上可以调用主线程上的方法。清洁。