I am looking to use Parse in my android application. I want to add offline support to the application, such that in offline mode the user stores the data locally, and when the application gets connected to the internet, we submit the data.
TodoItem todoItem = new TodoItem("Do laundry");
// Set the current user, assuming a user is signed in
todoItem.setOwner(ParseUser.getCurrentUser());
// Immediately save the data asynchronously
todoItem.saveInBackground();
// or
todoItem.saveEventually();
When i use save eventually, will Parse wait for the internet to connect to submit the data.
Kind Regards
Update 13-07-2018: Since the parse.com service was discontinued, I will provide the info from the parseplatform.org, the opensource implementation.
The app will try to save them in the background, and if it's offline, or closed, will try next time to save them.
Most save functions execute immediately, and inform your app when the save is complete. If you don’t need to know when the save has finished, you can use saveEventually instead. The advantage is that if the user currently doesn’t have a network connection, saveEventually will store the update on the device until a network connection is re-established. If your app is closed before the connection is back, Parse will try again the next time the app is opened. All calls to saveEventually (and deleteEventually) are executed in the order they are called, so it is safe to call saveEventually on an object multiple times. If you have the local datastore enabled, then any object you saveEventually will be pinned as long as that save is in progress. That makes it easy to retrieve your local changes while waiting for the network to be available.
You could also try to save them in local storage, and then save by yourself, which will do the work mentioned above.
Save eventually Doc
According to the documentation from http://parse.com/docs you need to call todoitem.saveEventually() if the device is offline. In case there is no connection, you might also save the data (temporary) in the local data store todoItem.pinInBackground();, so you can work with what you saved when the device is offline.
https://parse.com/docs/android_guide#objects-saving-offline
https://parse.com/docs/android_guide#objects-pinning
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
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.
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);
Is it possible to get Firebase remote config before starting an activity ?
I'm trying to get Firebase remote config inside a background IntentService before activity is started but onComplete() is never called.
FirebaseRemoteConfig instance stays in status FirebaseRemoteConfigInfo.LAST_FETCH_STATUS_NO_FETCH_YET
A fetch will take as long as a fetch takes. You get no guarantee about how long it will take, just like any other request to a server over a network. Your app should be prepared to work with default values you specify, or make your users wait for the fetch by using a splash screen that only advances when your fetch is done (this is not usually a good idea - better to work with defaults until the first fetch completes).
I thought the whole time when I used the following all data for chat conversation will be available offline at any time. Which somehow isn't and all nodes are loaded from the server.
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
Then, according to DOCS :
Persistence Behavior : By enabling persistence, any data that we sync while online will be persisted to disk and available offline, even when we restart the app. This means our app will work as it would online using the local data stored in the cache.
If data will already be available offline when setPersistenceEnabled(true); , why do I need keepSynced(true) ?
DatabaseReference r = FirebaseDatabase.getInstance().getReference("chat/roomid");
r.keepSynced(true);
The Firebase Database client in your app can keep the data from the database in two places: in memory and/or on disk.
When you attach a listener, it synchronizes data from the database to an in memory representation in your app.
If you've enable persistence, the data is automatically also persisted on disk.
When you detach the last listener from a location, the data for that location is flushed from memory. But it is not deleted from disk.
When you keep a location synchronized, the client essentially attaches an empty listener to that location. So the data in the app will always be up to date with what's in the database on the server (as long as there is a network connection). If you haven't enabled persistence, the data will just be kept up to date in memory. If you've enabled persistence, it will also be kept up to date on disk.
While it's most common to use keepSynced with persistence, there are also use-cases without persistence.
For example, if you have a master-detail app, where you frequently bounce from a list of item names to the details of each item. In that case keeping the list of item names synchronized will save you from having to reload that data when the user comes back from the detail screen.
You could of course also simply keep a listener on the data, which is essentially what keepSynced does behind the scenes.
According to Firebase documentation
By default the Firebase client will keep data in memory while your application is running, but not when it is restarted. By setting this value to true, the data will be persisted to on-device (disk) storage and will thus be available again when the app is restarted (even when there is no network connectivity at that time). Note that this method must be called before creating your first Firebase reference and only needs to be called once per application. If your app uses Firebase Authentication, the client will automatically persist the user's authentication token across restarts, even without persistence enabled. But if the auth token expired while offline and you've enabled persistence, the client will pause write operations until you successfully re-authenticate (or explicitly call unauth) to prevent your writes from being sent unauthenticated and failing due to security rules.
Note that it says the data will persist on disk and be available when apps restart. If you look at the life cycle of an Activity, you'll see that an activity stop when you change to other activity. So, as long as your app is still open and user only navigated to others activities, data will remain persisted.
But don't say anything about killing your app and persist data. That's why you need keepSynced():
By calling keepSynced(true) on a location, the data for that location will automatically be downloaded and kept in sync, even when no listeners are attached for that location. Additionally, while a location is kept synced, it will not be evicted from the persistent disk cache.
Pay attencion when it says "while location is kept synced, it will not be evicted from the persistent disk cache", this means that if you don't use keepSynced(true) your data could be flushed way when the app is killed/closed.
So, to persist and continue with data after your app is killed, you need to use both FirebaseDatabase.getInstance().setPersistenceEnabled(true); and keepSynced(true).
setPersistanceEnabled(true) It will store the data for offline use.
keepsynced(true) by default, Firebase keeps 10mb data in cache,if it grows further it will replace by new data.To avoid the same and keep the whole data keepsynced(true) will help You.