I am trying to observe on LiveData
within LazyColumn
, but that does not work.
However, outside the LazyColumn
that works. The same is when I do within LaunchedEffect
.
Perhaps, the CoroutineScope
and LazyScope
are triggered before items are observed. Am I right?
How to get items within the LazyColumn
or LaunchedEffect
?
Below my implementation.
Dao:
@Dao
interface ItemDao {
@Query("SELECT * FROM $ITEMS")
fun getAll(): LiveData<List<Item>>
}
Repository:
class Repository(private val itemDao: ItemDao) {
val getAll: LiveData<List<Item>> = itemDao.getAll()
}
DataModel:
class DataModel(private val app: Application) : AndroidViewModel(app) {
fun getAll(): LiveData<List<Item>> {
return repository.getAll
}
}
AppDatabase:
@Database(entities = [Item::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract val itemDao: ItemDao
companion object {
private const val ItemsDB = "Items.db"
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase = INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
ItemsDB
)
.build()
INSTANCE = instance
return instance
}
}
}
MyApp:
class MyApp : Application() {
lateinit var mDatabase: AppDatabase
override fun onCreate() {
super.onCreate()
mDatabase = AppDatabase.getInstance(applicationContext)
}
}
MainActivity:
class MainActivity : ComponentActivity() {
@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val dataModel = ViewModelProvider(this)[DataModel::class.java]
setContent {
MyAppTheme {
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
NavGraph(rememberAnimatedNavController(), dataModel)
}
}
}
}
}
NavGraph:
@Composable
@OptIn(ExperimentalAnimationApi::class)
fun NavGraph(controller: NavHostController = rememberAnimatedNavController(), dataModel: DataModel = viewModel()) {
AnimatedNavHost(controller, HOME) {
composable(HOME) { HomeScreen(controller, dataModel) }
}
}
HomeScreen:
@Composable
@Preview(showBackground = true)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
fun HomeScreen(controller: NavController = rememberNavController(), dataModel: DataModel = viewModel()) {
val items by dataModel.getAll().observeAsState(listOf())
Column(Modifier.fillMaxWidth()) {
Text(text = items[0].text) // This one works fine.
LazyColumn(Modifier.padding(start = 6.dp, end = 6.dp)) {
itemsIndexed(questions) { index, _ ->
Text(text = items[index].text)
}
}
}
LaunchedEffect(Unit) {
// items[0].count -> Does not work... :(
}
}
The problem could be that you are trying to access the first item in the list in LaunchedEffect, even though the list itself is not loaded. The problem can be solved like this:
LaunchedEffect(items) {
if (items.isEmpty()) {
// Your code if list is loading
}
else {
// Your code if list already loaded
}
}
Explanation: The code in LaunchedEffect is called only when the val items changes, in it we check if the list is empty, we can display the load animation, in the other case your code will be invoked
Also if variable questions doesn't used in your lazy column. Recommend to change it to itemsIndexed(items) { index, item -> }
If that does not help, please send the error log