Asynchronous operations not performing as expected- Kotlin Android

I have written a code to fetch data from Cloud Firestore and am trying to implement the network calls using coroutines. I have tried to follow the official guides as much as possible, but since the functions have been left incomplete in those docs, I have made adjustments according to my requirements, but those might be the problem itself.

Here’s the function which fetches the data:

    suspend fun fetchHubList(): MutableLiveData<ArrayList<HubModel>> =  withContext(Dispatchers.IO) {
        val hubList = ArrayList<HubModel>()
        val liveHubData = MutableLiveData<ArrayList<HubModel>>()
        hubsListCollection.get().addOnSuccessListener { collection ->

            if (collection != null) {

                Log.d(TAG, "Data fetch successful!")
                for (document in collection) {
                    Log.d(TAG, "the document id is ")
                    hubList.add(document.toObject(HubModel::class.java))
                }

            } else {
                Log.d(TAG, "No such document")
            }

        }.addOnFailureListener { exception ->
            Log.d(TAG, "get failed with ", exception)
        }


        if (hubList.isEmpty()) {
            Log.d(TAG, "Collection size 0")
        } else {
            Log.d(TAG, "Collection size not 0")
        }
        liveHubData.postValue(hubList)
        [email protected] liveHubData
        }

And here is the ViewModel class which is calling this method:

class HubListViewModel(application: Application): AndroidViewModel(application) {
    // The data which will be observed
    var hubList = MutableLiveData<ArrayList<HubModel>>()
    private val hubListDao = HubListDao()
    init {
        viewModelScope.launch (Dispatchers.IO){
            hubList = hubListDao.fetchHubList()
            Log.d(TAG, "Array List fetched")
        }
    }
}

Using the tag messages I know that an empty list is being returned, which I know from another question of mine, is because the returned ArrayList is not in sync with the fetching operation, but I don’t know why, since I’ve wrapped the whole function inside a with context block. Please tell me why the return and fetching is not being performed sequentially.

Answer

you should add this dependency "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.3". It allows you to use await() to replace callbacks.

suspend fun fetchHubList(): List<HubModel>? = try {
    hubsListCollection.get().await().map { document ->
        Log.d(TAG, "the document id is ${document.id}")
        document.toObject(HubModel::class.java)
    }.apply {
        Log.d(TAG, "Data fetch successful!")
        Log.d(TAG, "Collection size is $size")
    }
} catch (e: Exception) {
    Log.d(TAG, "get failed with ", e)
    null
}

Dispatchers.IO is not necessary since firebase APIs are main-safe

class HubListViewModel(application: Application): AndroidViewModel(application) {
    val hubList = MutableLiveData<List<HubModel>>()
    private val hubListDao = HubListDao()
    init {
        viewModelScope.launch {
            hubList.value = hubListDao.fetchHubList()
            Log.d(TAG, "List fetched")
        }
    }
}