- Offline persistence is supported only in Android, iOS, and web apps.
- For Android and iOS, offline persistence is enabled by default.
- Querying works with offline persistence.
Add data: autogenarated id and callbacks
The above code below should not be used when offline, as addOnSuccessListener
, addOnFailureListener
and addOnCompleteListener
shall not return as the backend could not be reached.
NOTE: The callbacks wouldn't work for add/set/update when offline, but callbacks for get/query still works.
NOTE: The callbacks will returned when the device goes online and completed the backed commit. Imagine you have done 100 save calls with callbacks when offline, then you get 100 callbacks get triggered when the device goes online. Or you save call get triggered 1h later when you get online. If you do use callbacks, make sure you are ready to handle these scenarios.
Besides, we cannot access the autogenerated id as well.
val db = FirebaseFirestore.getInstance()db.collection("test") .add(mapOf( "created" to FieldValue.serverTimestamp(), "posted_date" to Timestamp.now() )) .addOnSuccessListener { // will only run after committed to backend val id = it.id } .addOnFailureListener { // will only run after committed to backend } .addOnCompleteListener { // will only run after committed to backend }
The following code should be used, as we can now access the auto generated id.
val docRef = db.collection("test").document()val id = docRef.idTimber.d("id=$id")docRef .set(mapOf( "created" to FieldValue.serverTimestamp(), "posted_date" to Timestamp.now(), "name" to "test" ))
id=Xi3exHiSGViSi1SAQv4v
NOTE: Notice auto generated id works offline (without access to backend).
We can use the docRef
to perform a query.
docRef.get().addOnSuccessListener { document -> val id = document.id val created = (document["created"] as? Timestamp)?.toDate() val postedDate = (document["posted_date"] as? Timestamp)?.toDate() Timber.d("id=$id, created=$created, postedDate=$postedDate")}
id=Xi3exHiSGViSi1SAQv4v, created=null, postedDate=Fri Mar 01 17:37:11 GMT+08:00 2019
NOTE: Notice that created
(FieldValue.serverTimestamp()) is null, as backend server could not be reached.
You can use id
to perform a query as well.
db.collection("test") .document(id) .get() .addOnSuccessListener { document -> val id = document.id val created = (document["created"] as? Timestamp)?.toDate() val postedDate = (document["posted_date"] as? Timestamp)?.toDate() Timber.d("id=$id, created=$created, postedDate=$postedDate") } .addOnFailureListener { Timber.w(it) }
Server timestamp and query order
We shall perform a batch insert of documents using both server timestamp and local timestamp as well.
val batch = db.batch()for (i in 1..10) { val docRef = db.collection(Test.COLLECTION_NAME).document() batch.set(docRef, mapOf( "created" to FieldValue.serverTimestamp(), "posted_date" to Timestamp.now(), "test_offline_order" to true, "sequence" to i ))}batch.commit()
Query order by created
wouldn't work when offline (as it required a server to fill these values), so we have to query by posted_date
which used a local time.
db.collection("test") .whereEqualTo("test_offline_order", true) // .orderBy("created", Query.Direction.DESCENDING) .orderBy("posted_date", Query.Direction.DESCENDING) .get() .addOnSuccessListener { documents -> Timber.d("get: success") for (document in documents) { val created = (document["created"] as? Timestamp)?.toLocalDateTime() val postedDate = (document["posted_date"] as? Timestamp)?.toLocalDateTime() val sequence = document["sequence"] as Long Timber.d("id=${document.id}, created=$created, posted=$postedDate, sequence=$sequence") } }
NOTE: Refer to Timestamp.toLocalDateTime() Kotlin extension
.orderBy("created", Query.Direction.DESCENDING)
id=bvtL4yk3IaFvPGHp6V6v, created=null, posted=2019-03-01T16:18:21.896, sequence=4
id=agWieap4Xi95qnn4fYk5, created=null, posted=2019-03-01T16:18:21.895, sequence=3
id=Vw1XLwFB0cXOhbTkJiSg, created=null, posted=2019-03-01T16:18:21.911, sequence=8
id=So3ePFXP5nMAaKbAq4f1, created=null, posted=2019-03-01T16:18:21.894, sequence=2
id=NhnlAl7XPicINfzR1i85, created=null, posted=2019-03-01T16:18:21.915, sequence=10
id=KfOn2kS9dpNpMzr5hQ0S, created=null, posted=2019-03-01T16:18:21.913, sequence=9
id=Gyxnw0vD4dTuCYM8gOTs, created=null, posted=2019-03-01T16:18:21.906, sequence=6
id=FNxphM50s4yyyPsQccvw, created=null, posted=2019-03-01T16:18:21.855, sequence=1
id=5pSFOxspzl75hYZzjnut, created=null, posted=2019-03-01T16:18:21.898, sequence=5
id=4eSKFhSK8wvapwiz71TP, created=null, posted=2019-03-01T16:18:21.909, sequence=7
.orderBy("posted_date", Query.Direction.DESCENDING)
id=NhnlAl7XPicINfzR1i85, created=null, posted=2019-03-01T16:18:21.915, sequence=10
id=KfOn2kS9dpNpMzr5hQ0S, created=null, posted=2019-03-01T16:18:21.913, sequence=9
id=Vw1XLwFB0cXOhbTkJiSg, created=null, posted=2019-03-01T16:18:21.911, sequence=8
id=4eSKFhSK8wvapwiz71TP, created=null, posted=2019-03-01T16:18:21.909, sequence=7
id=Gyxnw0vD4dTuCYM8gOTs, created=null, posted=2019-03-01T16:18:21.906, sequence=6
id=5pSFOxspzl75hYZzjnut, created=null, posted=2019-03-01T16:18:21.898, sequence=5
id=bvtL4yk3IaFvPGHp6V6v, created=null, posted=2019-03-01T16:18:21.896, sequence=4
id=agWieap4Xi95qnn4fYk5, created=null, posted=2019-03-01T16:18:21.895, sequence=3
id=So3ePFXP5nMAaKbAq4f1, created=null, posted=2019-03-01T16:18:21.894, sequence=2
id=FNxphM50s4yyyPsQccvw, created=null, posted=2019-03-01T16:18:21.855, sequence=1