Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use Compose LazyColumn with Coroutines/Room Database?

I'm writing a simple app for myself to display an RSS feed as a list of items and figured it'd be a good opportunity to learn about @Compose lazyColumn. I'm blown away with how little code it is, no Adapter, no ViewHolder, no xml. Amazingly streamlined.

But how can you set it up to work with something like Room Database where you're using a coroutine to pull data from a database? The official documentation here talks about rememberCoroutineScope() but doesn't explain where you define it. Placing a coroutine inside the Surface definition feels weird, which is probably why it doesn't work. It yields a: @Composable invocations can only happen from the context of a @Composable function error.

Does this need to be done through a ViewModel? In the real world data from the repository will be coming from a ViewModel anyway, but for now I just wanted to display a simple of list of items pulled from the internet (ie, requiring a coroutine). But then how do you handle LiveData or List<String> from ViewModel/Database?

Does anyone know how to set this up? I feel it shouldn't be that hard, but I don't know where to start looking for answers.

Ex:

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) ... }
}
like image 399
dbarnes Avatar asked Sep 11 '25 17:09

dbarnes


1 Answers

@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) ... }
}

To understand what's going on here you need to check out about:

  1. Storing state in compose. remember { mutableStateOf() } is the simplest way of storing data between recompositions. But it'll be cleaned when you switch between views, so check out on view models too, which may suit better for your task. documentation
  2. LaunchedEffect is the preferred way to do any actions inside composable functions. Inside this block you're already in a coroutine, so can run suspend functions
  3. You don't need to define a coroutine for rememberCoroutineScope, it returns pre-initialized coroutine. Usually you need to use it for events like button press or touch
like image 190
Philip Dukhov Avatar answered Sep 14 '25 09:09

Philip Dukhov