Transforms Firebase Cloud Firestore queries, collections, and documents into LiveData
.
First, add the JitPack repository to your project-level build.gradle
file:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
To add FirestoreLiveData to your app, add the following dependency to your module's build.gradle
file:
implementation "com.github.ptrbrynt:FirestoreLiveData:$latestVersion"
The first step in transforming your Firestore queries is to create a model class. All model classes must extend FirestoreModel
in order to work with this library:
data class Book(
var title: String? = null,
var author: String? = null,
var timestamp: Timestamp? = null
): FirestoreModel()
It's also important not to include an 'id' property in your models, as this is included in FirestoreModel
.
You can transform any instance of Query
, CollectionReference
, or DocumentReference
into a LiveData
like so:
val db = FirebaseFirestore.getInstance()
val myQuery = db.collection("books").orderBy("title").asLiveData<Book>()
val myCollection = db.collection("books").asLiveData<Book>()
val myDocument = db.collection("books").document(documentId).asLiveData<Book>()
The asLiveData<T>()
methods return instances of LiveData<FirestoreResource<T>>
for documents, and LiveData<FirestoreResource<List<T>>>
for collections and queries.
The FirestoreResource
class wraps the result of your query or reference and includes some additional information:
val myQuery = db.collection("books").orderBy("title").asLiveData<Book>()
// In your fragment or activity
myQuery.observe(this, Observer { resource: FirestoreResource<List<Book>> ->
val status: Status = resource.status // Either SUCCESS, ERROR, or LOADING
val data: List<Book>? = resource.data // The result of your query or reference, when status is SUCCESS
val throwable: Throwable? = resource.throwable // If an error occurred, the details are here, when status is ERROR
val errorMessage: String? = resource.errorMessage // A shortcut to resource.throwable?.localizedMessage
}
As a helpful utility, the library also includes a ResourceObserver
class, which is an extension of Observer
and provides easy callbacks for the three states.
You can implement a ResourceObserver
like this:
myQuery.observe(this, object: ResourceObserver<List<Book>> {
override fun onSuccess(data: List<Book>?) {
// Handle successful result here
}
override fun onError(throwable: Throwable?, errorMessage: String?) {
// Handle errors here
}
override fun onLoading() {
// Handle loading state e.g. display a loading animation
}
}
If you have an instance of CollectionLiveData
, you can add a new object to the collection like this:
val myCollection = db.collection("books").asLiveData<Book>()
myCollection.add(Book("A Book", "An Author", Timestamp.now()))
Similarly, you can perform the following operations on DocumentLiveData
:
val myDocument = db.collection("books").document(documentId).asLiveData<Book>()
// Replaces the current data
myDocument.set(Book("Another Book", "A Superior Author", Timestamp.now())
// Update the value of a field
myDocument.update("title", "Updated Title")
// Update the values of multiple fields
myDocument.update(mapOf(Pair("title", "Updated Title"), Pair("author", "New Author")))
All the operations described above return TaskLiveData
instances. These are LiveData
s containing TaskResult
s, which are a bit like FirestoreResource
s, but for Task
s!
val task = myDocument.update("title", "Updated Title")
task.observe(lifecycleOwner, Observer { taskResult ->
val status: TaskStatus = taskResult.status // Either SUCCESS, CANCELLED, FAILED, or RUNNING
val data = taskResult.data // The data attached to the result of the task. Only present for add operations on collections, and will be the reference to the newly added item
val exception: Exception? = taskResult.exception // If an error occurred, this exception will provide information
})
Also included is a LiveData
wrapper for the current FirebaseAuth
state:
FirebaseAuth.getInstance().currentUserLiveData.observe(lifecycleOwner, Observer {
// Handle auth state changes here
})
Also included is a handy shortcut to translate Query
s, DocumentReference
s, and CollectionReference
s into LiveData
and observe them, as one function call!
val myQuery = db.collection("books").orderBy("published")
myQuery.observe<Book>(lifecycleOwner, Observer { books: FirestoreResource<List<Book>> ->
// Here are the books!
})