Android Firestore Query addSnapshotListener as LiveData (lifecycle aware)

May 14, 2019
QuerySnapshotLiveData

Extend LiveData

class QuerySnapshotLiveData(private val query: Query) : LiveData<Resource<QuerySnapshot>>(),
    EventListener<QuerySnapshot> {

    private var registration: ListenerRegistration? = null

    override fun onEvent(snapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {
        value = if (e != null) {
            Resource(e)
        } else {
            Resource(snapshots!!)
        }
    }

    override fun onActive() {
        super.onActive()
        registration = query.addSnapshotListener(this)
    }

    override fun onInactive() {
        super.onInactive()

        registration?.also {
            it.remove()
            registration = null
        }
    }
}
class Resource<T> private constructor(
    private val data: T?,
    private val error: Exception?
) {

    val isSuccessful: Boolean
        get() = data != null && error == null

    constructor(data: T) : this(data, null)

    constructor(exception: Exception) : this(null, exception)

    fun data(): T {
        if (error != null) {
            throw IllegalStateException("Check isSuccessful first: call error() instead.")
        }
        return data!!
    }

    fun error(): Exception {
        if (data != null) {
            throw IllegalStateException("Check isSuccessful first: call data() instead.")
        }
        return error!!
    }
}

Usage

fun fetchLiveData(): QuerySnapshotLiveData {
    val query = firestore.collection("users")
        .whereEqualTo("is_active", true)
    return QuerySnapshotLiveData(query)
}
fetchLiveData().observe(owner, Observer { result ->
    if (result.isSuccessful) {
        // do something
        val query = result.data()
    }
    else {
        Timber.e(result.error())
    }
})

Add Kotlin Extension

fun Query.asSnapshotLiveData(): QuerySnapshotLiveData {
    return QuerySnapshotLiveData(this)
}
fun fetchLiveData(): QuerySnapshotLiveData {
    return firestore.collection("users")
        .whereEqualTo("is_active", true)
        .asSnapshotLiveData()
}

NOTE: Refer to Firestore addSnapshotListener with LifecycleOwner.

References:

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.