so I'm working with realtime database and I'm trying to make a chat app for practice.
I want to add the message to my list then let the message item inside the list upload the message to the server, I'm also showing an indicator that tells the user if the message is being uploaded, there are other approaches to apply this but I want to go with this one, anyways.
there isn't any problem when there is an internet connection. the problem is when there isn't any internet connection, the message is added to the list and the indicator appears, when the internet connection returns everything works fine still.
but if I send a message (while offline) and then leave the chat room and return to the chat room, the messages will get loaded and the indicator won't appear altho it isn't uploaded to the server (the data is cached now).
I want to find a way to tell if the data has been uploaded or not? I don't want to check the server to see if the node exists, I can't do that to every message it will cost too much, thank you.
If you enable disk persistence, Firebase keeps all of its pending writes in its disk cache. When the app restarts, it reads those pending writes and starts trying them. This is usually the right behavior for your users.
Unfortunately there is no built-in way to persist completion handlers for the Realtime Database. So upon a restart it becomes impossible for you to detect when the pending writes have been committed on the server.
So this typically means that you need to do something custom to detect the situation, and will have to determine for yourself whether the use-case is worth the effort.
If your messages are in some way ordered/timestamped (for example, if you add them by calling push()) you can keep track of what the last message is for which you received a confirmation from the server. That way you will know when the client restarts, which messages may not have been sent to the server yet.
Your onDataChange or onChildAdded will be called for those unconfirmed message straight away though when your app restarts, so you'll need an additional mechanism to detect when those unconfirmed messages are written on the server.
The best approach I know if is to write a "dummy" message when the app starts. Since the pending writes are treated as a first-in-first-out queue, your new dummy message write will be sent to the server after all the pending writes from the previous run. So when your completion handler gets called for this dummy message, you can be sure that all messages before it have also been committed (or rejected in case they violate your security rules).
Firebase cloud functions fires an onFinalize event when a file has been uploaded to the storage. So you could probably write a cloud function like this.
exports.uploadedServer = functions.storage.object().onFinalize((object) => {
const filename = object.name
//mark this filename or filekey as upload complete
return
})
You should be able to find more explanation here.
Related
I'm writing a chat application with the help of firebase.Here I have a problem , if the device is offline the data is stored in cache and when device is back online the cache will be synced , but how to know which data is synced and which not (User may have poor internet connection , so syncing may be delayed).How to notify user that message has been sent or sending , and that too we need to manage a huge list of messages
Thank you!
There are two ways:
Using a completion listener as shown here: Firebase Android - how to tell if node has been synced This approach works as long as the app stays active. Completion listener don't survive an app restart, so it won't work if the app is restarted.
Using a sentinel value. Writes to the database from a single client are guaranteed to be executed in order. Using this knowledge, you could write a sentinel (think: dummy) value when the app is restarted, or the connection is restored, and detect when that one is written. Once the sentinel value is confirmed, you can be certain that all older messages have also been handled by the server.
Also see:
Firebase synchronisation of locally-modified data: handling errors & global status
I am making an app which uses firestore in am using onSuccessListener just to know if task was successful and then show a toast message , and onFailtureListener just to know if it was unsuccessful and then show toast for that , but can i remove those listeners and assume that data will be written always and fetched always if i know the references will always be valid.
Or in other words in what situations my onFailureListener will trigger.
I am facing one more problem , because of offline support the new data immediately shows up in UI even if the user is offline which is good but the onSuccessListener only triggers when user get back online,
showing data in UI should mean that the task was successful and onSuccessListener should be triggered online.
Isn't it wired the user sees the data in UI and thinks it was added successfully and after a minute when he gets back online he sees a toast saying data was added , and now he thinking which data?
You cannot assume that any write will eventually succeed. The most common cases for Firestore write failures are violations of security rules, and exceeding some limit (such as individual write limits for a document).
You can see a list of all the possible errors in the API documentation for FirebaseFirestoreException.Code.
I'm using Firebase's realtime database on Android and the way I understand how it works is that even if the app disconnects from the network, Firebase will simply queue the transactions that the user has initiated and then perform then when connectivity is resumed. This works really well but if the app is closed then this queue seems to be discarded.
The Firebase docs on handling offline capabilities states the following:
Transactions are not persisted across app restarts
Even with persistence enabled, transactions are not persisted across
app restarts. So you cannot rely on transactions done offline being
committed to your Firebase Realtime Database. To provide the best user
experience, your app should show that a transaction has not been saved
into your Firebase Realtime Database yet, or make sure your app
remembers them manually and executes them again after an app restart.
But as far as I know, there is no way of knowing whether or not data has finished being written to the database.
How exactly would you go about making the app manually remembering what still needs to be written to the database? Is there some way of accessing the queue of transactions that is yet to be carried out? Or is there some way of keeping the app running in the background after being closed that could just sync the data when connectivity resumes?
Thanks in advance.
But as far as I know, there is no way of knowing whether or not data has finished being written to the database.
There actually is. The Transaction.Handler interface has a [onComplete method](https://firebase.google.com/docs/reference/android/com/google/firebase/database/Transaction.Handler.html#onComplete(com.google.firebase.database.DatabaseError, boolean, com.google.firebase.database.DataSnapshot)). The boolean that is passed to that argument is a flag to indicate if the transaction was committed:
committed
True if the transaction successfully completed, false if it was aborted or an error occurred
For more information, see the Firebase documentation on transactions.
I think I had the problem you are facing, in my case was a simple confusion. That Firebase warning is not about "transactions" in general, is about the "transaction" method provided by them.
In Android this is reference().runTransaction().
The "transaction" method is used to validate data first, by example, if more than one user can subscribe to an event simultaneously, you can make sure that the last vacant was available.
Since the "transaction" method query the database gives you the data, and the upload data, if there is no network connectivity there is no way to make sure that will work on app restart because there was never a first query to see the data you have to validate.
This seems logical to me, a "transaction" method will create a sort of bridge between the client and the database, this is not random, but because is part of the business logic, then you should warn the user visually that their changes might not be saved since it is offline, or even if it is sensitive not allow the user to do it.
In other cases, the data is indeed stored locally and then uploaded when the app is restarted. So if you do something like
reference.child(key).setValue(myObject);
Thant change will be local until the next time user has an internet connection.
You have to make sure to add the keepSynced to the references you actually need. Setting the syncing to the root, won't solve the problem as a waterfall, make sure to be specific with nodes you need to keep synced, this way the user will see the changed reflected visually in the app.
//Won't work
DatabaseReference root = FirebaseDatabase.getInstance().getReference();
root.keepSynced(true);
//This will work
root.child("event_list").keepSynced(true);
root.child("user_events").child(uid)keepSynced(true);
So, I want to learn this synchronization strategy instead of just using the simpler MessageAPI, but am really struggling with how to successfully implement this.
My project is like this: I make queries to download a small amount of text from an API, via my phone. I will make these queries every so often, haven't really decided on how often just yet. The data will update the watch, which should hold onto the last data received. After that first download occurs, I send data using a DataMap, to the Android Watch. I only send that once, because I believe that sets up a channel to continually send updates when ready. If that is wrong, please correct me.
My main question is this: what if the Android phone's app closes? Then the data object goes to null, and gets sent to the Watch as null? Or, should I send an object from a long-running service or shared preferences on the Android phone, so that the object is never null?
Think of the Data Layer as more of an event system, i.e., you update your data and you're notified on the other side when the data is updated (created, changed, or deleted). You don't have to worry about if the Activity is killed after that. Even if the data was 'deleted', you would be notified it was deleted.
On the Wear device, you would listen for the changes via a Service or Activity and update UI, DB, etc. accordingly.
It probably make sense to read through this Android training guide. (It isn't too long.) The Handling Data Layer Events section is probably the most useful.
I've got a large mailbox being managed by a custom android Exchange EWS client.
Due to client constraints the mailbox is only syncing 100 messages at a time. In one test account there are over 10,000 messages.
The problem I'm experiencing is that when new messages arrive and they are marked as read in a browser based client, the read state change doesn't seem to be being sent to the Android client unless the mailbox has already been fully synced.
When the mailbox isn't fully synced, it doesn't seem to receive the "read state" changes until all the items from the mailbox are synced.
What's the best way to solve this problem? I'm thinking I have to sync all message headers to the android client. This may clear the sync queue, so the read state changes are ready to be received.
Any suggestions?
The answer is as I expected - I needed to sync all messages (just their headers) to the client. I discarded the messages that fell outside of my desired date range. Then the read state changes came through automatically.