skip to Main Content

I am building an Android application using Jetpack compose library with Firebase. I’m rebuilding the app based on this sample builder Make it so Android.

I want to query a collection on firestore with the name "courses" (Number of documents in it is 1), but when I run the program it doesn’t show any documents and it doesn’t give me any error.

This is my firestore and rule:

enter image description here

enter image description here

And here is my code:

  1. CoursesServiceImpl.kt
package com.tnmd.learningenglishapp.model.service.imple

class CoursesServiceImpl @Inject
constructor(private val firestore: FirebaseFirestore, private val auth: AccountService
) : CoursesService {

    override val courses: Flow<List<Courses>>
        // I try to query in this
        get() = firestore.collection(COURSES_COLLECTION).dataObjects() 


    override suspend fun getCourses(coursesId: String): Courses? =
        firestore.collection(COURSES_COLLECTION).document(coursesId).get().await().toObject()


    override suspend fun save(courses: Courses): String =
        trace(SAVE_COURSES_TRACE){
            firestore.collection(COURSES_COLLECTION).add(courses).await().id
        }

    override suspend fun update(courses: Courses): Unit =
        trace(UPDATE_COURES_TRACE){
            firestore.collection(COURSES_COLLECTION).document(courses.id).set(courses).await()
        }

    override suspend fun delete(coursesId: String) {
        firestore.collection(COURSES_COLLECTION).document(coursesId).delete().await()
    }

    companion object {
        private const val USER_ID_FIELD = "userId"
        private const val COURSES_COLLECTION = "courses"
        private const val SAVE_COURSES_TRACE = "saveCourses"
        private const val UPDATE_COURES_TRACE = "updateCourses"
    }
}
  1. CoursesViewModel.kt
package com.tnmd.learningenglishapp.screens.list_courses

@HiltViewModel
class CoursesViewModel @Inject constructor(
    private val coursesService: CoursesService,
    logService: LogService
) : LearningEnglishAppViewModel(logService){

    val courses = coursesService.courses
}
  1. CoursesScreen.kt
package com.tnmd.learningenglishapp.screens.list_courses

@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
@ExperimentalMaterialApi
fun CoursesScreen(
    modifier: Modifier = Modifier,
    viewModel: CoursesViewModel = hiltViewModel()
) {
    Scaffold(
        floatingActionButton = {
            FloatingActionButton(
                onClick = { /*viewModel.onUpdateClick(openScreen)*/ },
                backgroundColor = MaterialTheme.colors.primary,
                contentColor = MaterialTheme.colors.onPrimary,
                modifier = modifier.padding(16.dp)
            ) {
                Icon(Icons.Filled.Add, "Update")
            }
        }
    ) {
        val courses = viewModel.courses.collectAsStateWithLifecycle(emptyList())

        Column(modifier = Modifier
            .fillMaxWidth()
            .fillMaxHeight()) {
            Text(text = courses.value.size.toString(), color = Color.DarkGray)
            LazyColumn {
                items(courses.value, key = { it.id }) { coursesItem ->
                    CoursesItem(
                        courses = coursesItem
                    )
                }
            }
        }
    }
}

I want to query a collection on firestore with the name "courses" (Number of documents in it is 1), but when I run the program it doesn’t show any documents and it doesn’t give me any error.

2

Answers


  1. Query takes time to load data from firestore as any other apis takes. So we have to do that work in a suspended function to wait for its completion. And due to this as you are not waiting it gives you empty list. You should do these following steps:

    Step 1. Make the CoursesService.courses function suspended using suspend keyword in the interface as well and change the return type to List<Course> of function to as it is not update it will give complete list ones in this case. You can do it like this:

    override suspend val courses: List<Courses>
    

    Step 2. Also make the courses variable of type MutableSnapshotList<Course> this will recompose the composable to show that updated list like this:

    val courses = mutableStateListOf<Course>()
    

    Step 3. Also get the data in coroutineScope as the suspended function needs for that you need to create separate function in viewModel or use init function to call CoursesService.courses function and remember to add the new data in the list as the list is val like this:

    init{
        //...
        viewModelScope.launch{
            //...
            courses.addAll(coursesService.courses)
        }
    }
    

    Step 4. Now you have to wait for the query to complete and you can use .await() function on the Result and then convert it into list like this:

    //...
    get() = firestore.collection(COURSES_COLLECTION).get().await().dataObjects()
    
    Login or Signup to reply.
    1. Make sure the document id is correct.

    2. Set FireStore rules to allow read, write if true;

    3. You can call all documents in a collection like this:

       db.collection("courses")
       .get()
       .addOnSuccessListener { result ->
           for (document in result) {
      
           }
       }
       .addOnFailureListener { exception ->
           Log.d(TAG, "Error getting documents: ", exception)
       }
      

    Check for any exception and if not, log your document in success listener.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search