I was building a chat application in Android using Firebase. When we use Firestore SDK, it triggers any listeners on updates as soon as data is written into local Firestore cache. Since I have included server-time in the field, a second trigger will occur when the data has actually reached server, since server-time gets updated there. Is there a possible way for me to distinguish between these two triggers, so that, I can update the user that the message reached the server (like WhatsApp).
If this is absolutely not possible, I have two options:
Use custom cloud functions to send the message, so that listener triggers only after data has reached the server. Until then, I can show pending status for user.
Use custom cloud functions that triggers on Firestore writes at that location, and sets a flag, which indicates the data has reached the server.
If I have choose, which is better?
You can determine whether a snapshot is guaranteed to be up-to-date with the server by checking the isFromCache() and hasPendingWrites() methods in its metadata.
Related
My current android app is azure mobile app where a user can book any service.I need to show the status of his order like booked,pending completed in a fragment.I am right now doing it by calling api but everytime fragments gets created it calls api even if no data is changed.What is the possible and efficient solution of doing this.
For your scenario, the orders data are stored in your server-side database. Though you could store the retrieved order data into the local storage (e.g. SQLite,etc) on your mobile client, in order to retrieve the latest order status, you must explicitly call your mobile app backend for retrieving the latest order info and update your local order status. At this point, you could try to decrease the response data size returned by your backend via specifying minimum fields in your request. Details you could follow the .select() field selection clause.
Moreover, you could also follow Khemraj's suggestion about the notification approach, but the push notification may needs user interaction.
I'm writing an Android application that uses the Firebase RealTime Database and Firebase Cloud functions. Several of my cloud functions are triggered by writes to the RealTime database and are used further process data saved by the Android client application.
I'd like my app to handle network connectivity changes gracefully. I understand that Firebase handles loss of connection by saving changes to the RealTime database locally and then syncing the changes to the server when connectivity is restored. This is well documented in the Firebase Documentation.
In my case though, since I need the Cloud Function post-processing of data saved to some paths to have occurred before it is useful, there's no point in having this data saved if it isn't going to make it to the server (and therefore trigger a Cloud Function), in a timely manner.
I'm using the updateChildren function from DatabaseReference to save the data and have a CompletionListener attached to monitor the outcome. I thought I may be able to use the DISCONNECTED and/or NETWORK_ERROR DatabaseErrors to identify cases where my data won't be reaching the server. However, if I interrupt the network connection before updateChildren is called, there aren't any errors generated. In this case, Firebase has likely saved the data locally with plans to sync it later, so updateChildren is considered to have been completed successfully.
My questions then are:
When are the DatabaseErrors DISCONNECTED and NETWORK_ERROR actually used by Firebase? Can I use them in some way to help manage connectivity issues?
What are the best practices for handling cases where Firebase data must make it to the server in order to be useful? Should I really just be POSTing my data to the Cloud Function directly?
Does Firebase have any notion of a timeout period that can be watched and data invalidated if it isn't synced within a specific period of time?
Yes, I recognize that I can use a listener attached to /.info/connected to detect changes in the connection state, but I'd rather be able to react and gracefully handle my case as it happens. I feel that my usage of the Realtime database together with Cloud Functions is common enough that there must be generally accepted way to implement it.
Any thoughts appreciated. Many thanks.
Did you try OnDisconnect method of firebase realtime database ?
I'm building a chat using Firebase, using offline feature (keepSynced(true))
It works very well except that I cant find a way to know if the DataSnapshot message has indeed been saved server side, as if I query for the message Firebase will tell me that it exists (it does locally!).
I found about transactions but it does not save offline.
I also found about checking the connection status of Firebase, but it is a global status, and does not reflect one by one snapshot status.
The only solution that I found is adding a property "persisted" on my message objected, this property being set by a server side function, but that seems overkill for this purpose. I'm pretty sure Firebase does know locally which values are not persisted yet ?
On Android, when you perform any operation that writes, you will either get a Task object in return, or you may specify a CompletionListener as an argument. Either of these will indicate when the data is received by the server. If you don't use these, you have no other indication.
Using a Cloud Function to tag the location upon write is certainly another way to do it, if you can't hold on to the Task or CompletionListener.
I'm trying to find out how far the offline capabilities of Firebase on Android actually go.
As far as I understand, it should be possible to make the Database "persistent" with FirebaseDatabase.getInstance().setPersistenceEnabled(true);
The documentation reads:
The Firebase Realtime Database stores data returned from a query for use when offline. For queries constructed while offline, the Firebase Realtime Database continues to work for previously loaded data. If the requested data hasn't loaded, the Firebase Realtime Database loads data from the local cache. When we come back online our data will load and reflect the query.
Is this also true when the offline state is beeing forced by goOffline?
In this question the user got an answer from firebase support:
While you can use goOffline() to force the client offline for a long time, performance will deteriorate over time. The Firebase clients will queue intermediate state changes, instead of updating the stored state as the server does.
Does this mean the "local database" isn't actually updated like it would be when offline due to connection loss?
Because most of the time any query or value event listener doesn't come back, onDataChange is never called as is onCanceled (I checked!)
If only the connection is lost, it actually works as advertised, although sometimes with up to a minute delay, which seems to be a problem on its own.
What is then the intention of even offering the goOffline() method if this just stops the interaction with the database completely?
In my implementation the app starts offline, with an anonymous authentication. So in the beginning of course the "local database" will be completely empty. But shouldn't the value events at least fire onDataChanged with an empty datasnapshot?
I tried staying online until I received the anonymous UID and added an empty entry into firebase database, which then is queried/cached. After that if I call goOffline, no more entries can be added and no more queries will be answered.
Similar to the above mentioned question, my plan is to offer the user the option to stay offline, with of course the downside of the build up of stored write events in the local cache (but that shouldn't be that big of a problem as there isn't that much data)
So how can I make this work if even possible at all?
The only thing I can see is to have some different database solution in the beginning for actual offline capabilities which has to be translated & transferred to firebase when the user chooses to go online.
I know that this question has been asked too many times, but I think the issues I'm trying to target are a little bit different, maybe more complicated.
I am going to develop an application that uses a RESTful Web Service and needs to have the following requirements:
the app should show some books, their authors and their editors in lists and in detail
the app should also allow searching for a book
books, authors and editors are fetched from a RESTful web service
every entity has to be cached so that when I open an Activity I see the old data first (if any), while the new one updates from the network.
every time an entity is updating, the interested parties should be notified (ContentObserver? A regular Listener implementation?)
if a call is already executing (say to api/books/1337 or to api/editors) the caller should be notified that it is loading data and should be given the old one (if it exists), as if it was the original caller.
some data (only books and authors) should be updated every N minutes (decided by the user) and the observers should be notified (SyncAdapter?)
Questions:
After watching and studying all of the components proposed by Virgil Dobjanschi at Google I/O 2010 here are my doubts:
How can I transparently handle the "entity-is-updating" concept for any caller? Should I use ContentObserver on a ContentProvider I will have to implement?
If I use a ContentObserver I can easily set a status-flag for the single entity (as suggested by Dobjanschi), for example UPDATING, INSERTING, and so on. But how should I handle list? Say I want a list of books, where should I put the status flag? Should I put it in a status table for lists only? If so, I should observe two Cursors, one for the status and one for the actual list (i.e., the table/Content URI). And what if the entity I'm asking for does not exists (yet) or the REST call returns a 404? How do I handle the callback?
If I put all of my REST methods in a **SyncAdapter**, can I "force" the SyncAdapter to update an entity/entity list from the network (and therefore put it into the proper table)? This way, the status flag would be useful.
Can the SyncAdapter work on multiple entities (actually, entity lists, as I want to update books and editors every now and then), since it only has a performSync method?
If my SyncAdapter implementation has been disabled by the user in the device settings it won't update anything (and that's fine). But if the user clicks on an "update books" button in an Activity, can I still call the performSync method, or will it be disabled as well?
SyncAdapter is a design pattern involving five components:
An app. This uses a set of Activity along with Cursor and ContentObserver and maybe CursorAdapter and some to provide a UI to the locally stored data from a ContentProvider.
ContentProvider The local device's data-store. Handles CRUD calls, handles notifying SyncAdapter of the need to push an update to the server.
Account The user identity on the remote server.
SyncAdapter A background process which runs, and keeps the local datastore in sync with the server.
The server itself.
So. To the questions:
"Is-updating" means, "has local changes which have not yet been pushed to the server. It's a flag you set on a row in your database. It's set in ContentProvider when you Create/Update/Delete a row. When SyncAdapter runs, it sees the flag, pushes the update to the server, clears the flag. The flag itself does two things:
a. Tells the user the app is busy saving the change, and when that's done.
b. Marks the row as changed so SyncAdapter knows to push it to the server.
Read here for more details.
If you're not syncing the entire catalog, then your client will directly query the server and cache the results by putting them into the ContentProvider. There is no status flag there, since they're coming from the server and therefore match the server state. Write your SyncAdapter to ignore them, or perhaps discard them after they've been cached a few days.
a. To ensure your local updates get sent to the server, you write your ContentProvider to notify the SyncAdapter during the ContentProvider's Create/Update/Delete calls. (Read here...)
b. To ensure you get updates from the server periodically, you configure the account for automatic sync. (Read Here...)
Yes. performSync is just a function call. Write it to do what you want. Have it fetch table 1 from the server and put it into one table in your ContentProvider. Then have it fetch table 2, and put it into a different table. Etc.
a. You can force a sync by calling ContentResolver.RequestSync() with ContentResolver.SYNC_EXTRAS_MANUAL in the extras bundle.
b. You can manually fetch something with client code and directly push it into the ContentProvider.
If you take a look at Running Sync Adapter section in Google Developers Training, you will find a whole detailed description of how to:
Run the Sync Adapter When Server Data Changes
Run the Sync Adapter When Content Provider Data Changes
Run the Sync Adapter After a Network Message
Run the Sync Adapter Periodically
Run the Sync Adapter On Demand