Create a class to handle data state (loading, error, success), as I believe it is impossible to handle exception within composable.
enum class Status { SUCCESS, ERROR, LOADING}// https://github.com/android/architecture-components-samples/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/vo/Resource.ktdata class Resource<out T>(val status: Status, val data: T?, val message: String?) { companion object { fun <T> success(data: T?): Resource<T> { return Resource(Status.SUCCESS, data, null) } fun <T> error(msg: String, data: T?): Resource<T> { return Resource(Status.ERROR, data, msg) } fun <T> loading(data: T?): Resource<T> { return Resource(Status.LOADING, data, null) } }}
Data Class
data class Post(var id: String, var created: Timestamp? = null, var title: String? = null) { companion object { fun toObject(doc: DocumentSnapshot): Post? { val item = doc.toObject<Post>() item?.id = doc.id return item } }}
ViewModel to load data from Firestore using Flow
class MainViewModel : ViewModel() { // consider using Dependency injection with Hilt private val auth: FirebaseAuth = Firebase.auth private val db = Firebase.firestore fun fetchPosts() = callbackFlow { val collection = db.collection("posts") val snapshotListener = collection.orderBy("created", Query.Direction.DESCENDING).addSnapshotListener { value, error -> val response = if (error == null && value != null) { val data = value.documents.map { doc -> Post.toObject(doc) } Resource.success(data) } else { Timber.e(error) Resource.error(error.toString(), null) } offer(response) } awaitClose() { snapshotListener.remove() } }}
Composable
@Composablefun JourneyApp(viewModel: MainViewModel = viewModel()) { val postsResource by viewModel.fetchPosts().collectAsState(initial = Resource.loading(null)) val posts = postsResource.data ?: emptyList() if (postsResource.status == Status.ERROR) { Text("Error: ${postsResource.message}") } else if (postsResource.status == Status.LOADING) { Text("Loading ....") } else { LazyColumn { items(posts) { post -> Text(post.title) } } }}