So I have discovered that an app can be updated whilst the app is in mid-use. My app records a workout and stores values into a local DB before uploading the workout.
During the last update, we altered the databases, adding new tables and columns. A certain number of users had their app update mid-workout, corrupting the database. While that can be fixed after the fact, it doesn't change the fact that the user has lost that workout. I've been searching but haven't yet found something that would allow for the app to wait on the update until it isn't in use.
Any suggestions are welcome.
Thank you for your time.
You can't stop the update, but you can make sure, there is no corruption, and there is no data lost: Before Update, the application's onPause() callback will be called - time to make sure, the App is in a recoverable state. This might include storing the momentary working set to some temp storage. After update, the app will receive onResume(), where you can load the working set back.
Related
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);
I have a bit of a problem:
I am working on an instant chat application for android where I need to make sure that a user gets deleted from the database as soon as he or she closes the app. There is this line of code:
Firebase.Instance.CurrentUser.Delete();
Which deletes the current user. I could put a LogOut button and have this line integrated into the Onclick Event which will delete the user from the database. But chances are that peeps won't click that button but instead just close the app from the taskmanager. (Or maybe their phone runs out of battery?)
Well, the problem is obvious: I cannot have more than 100 users connected to my server ( for monetary reasons), so it is vital for me to have the user and all of his records deleted upon closure of the app.
My next thought was to put the above line of code into the OnDestroy() Method, yet I came to realize that this method is sometimes not called and also doesn't seem to be able to delete the user even when called (Maybe it is too much work? I don't know).
What else could I be trying?
You are solving imaginary problem. You cannot have more than 100 users actively connected to the Firebase at the same moment, but you can have more than 100 users.
You don't need to delete users, you need to detach all observers in onPause() and that is all.
I am currently developing an RPG game for Android devices and have just implemented a custom method of serialisation I use for saving the player's progress. The saving process can take up to half a second which is enough time for a crash to occur (either caused by the device (i.e. low battery power off), the user (killing the app) or a poorly written firmware/ROM (kernel panics) etc).
While saving the player's data, the old player data is overwritten. This means if a crash was to occur, and if the saving process were to be cancelled/interrupted as a result, the player's data would be lost. This is obviously not ideal and in the future, the game will be saving a lot more data and the save time will be much longer. This will increase the chance of a crash occurring during the save process.
I cannot reduce the save time as I am writing the minimal data the game requires to be able to resume after the app has been restarted.
What foolproof measures, if any, can I take to prevent such data corruption/loss from happening?
You can save your data in a temporary set of files and moving/renaming them when the process is complete, then deleting the previous save files.
If you're not confident with the renaming process, you can add these constraints :
ensure that data is consistent with a checksum
always try to resume from the last consistent saved state, depending on a rule of your own (name of the file, ...)
Another idea would be to cut into pieces your data in order to isolate state that do not change.
If save time is really long, you can try to use remaining CPU time during the game to pre-save parts of the current state that won't probably change (using a lower priority Thread, for instance).
You can save data to a SQLiteDatabase. If changes to the save data fails or is interrupted, the database will automatically be rolled back to a previous known state.
For additional security if you need to perform multiple updates atomically, put all your changes into a transaction. If any of the changes fail, the entire transaction will be rolled back to the pre-transaction state.
For more information about using SQLite, see documentation here. For easier manipulation of your save data in the event you want to share it with other apps or sync it to a backup server, consider interacting with your data via a ContentProvider.
Im am developing a webservice for an App that I am writing. I want to make the App offline accessible.
I made that webservice so that if you request JSON from the webservice you can give a date:
/color/colors/date/2014-03-01T12:00/
If you don't give the date you will get everything that is inside the database and that is active. If you give the date you will only get everything that is updated after that date.
Now my problem is that if I remove something from the webservice of from the App then it will not be synced and the other devices will never know that it is removed.
I could work with a field where I say that a record is removed but then I need to keep every record and I can't delete any record.
Is there a better way to do the syncing? Or what is the best way?
I think there is no possible way to detect the deleted entry's change, unless you send the information that the entry is deleted. The best practise you set a field in the table with integer type, then you can set this value on updates. You don't have to set it only 1 or 0, you can use bigger numbers (for example I used 30 on that entries, that I deleted on 20th march , on this day was a big code logic change. after that i knew when the status integer is 30, then i deleted this row after that date.) It may be a silly example, but you can implement your own logic.
It depends on how important it is to update the rest of the devices when a change is made.
If it is critical, then it would be worth implementing push notifications or something similar to each device to let them know about the updated situation. Otherwise, you would simply have the other devices poll the server to check for changes on their own accord, and the frequency or the trigger of this poll would depend again on how critical it was that they get an update. Maybes they only need updating when they visit a certain activity, so in that case you would only poll when you reach the onResume() event of that activity
Update
If you don't need to keep a history of the deleted record, then why can't you just delete it, and then when the rest of the devices update, you clear all and download a fresh set? If that is too intensive, you would NEED to have a reference to the id, which you could do in a table or use a special value in the field (like null, 0 or -1) to mark it. Otherwise there would be no way to reference it
I am developing an android app and I need to save data when user is making a market update. Actually before the update is started. I tried using onDestroy() but that is not called when the app is updated. Do you have any ideas?
The problem is the app is saving data on a regular basis. And sometimes it happens that when you go and select update it tries to save on a file at the same exact time causing the data to get corrupted ... That's why I am trying to detect the update event.
File is saved at a fixed interval using a scheduled thread (e.g. 60 seconds). Also in the file I save a serialized Object using the classic writeObject(). This is happening only at a fixed rate of 60 seconds and also on the activity's onPause or service's onDestroy().
However if the fixed rate save happens exactly when updating (which causes the app to be destroyed) then the save is incomplete and the object get corrupted causing the next time the app is started to get an invalid object from the save file.
A general approach to save your data (from the Android developpers documentation) on android is to either use:
a key-value pairs on the shared preferences
saving the data on a files
or using a SQLite dabtase
You should use those even during the regular activity lifecycle and I dont see why they would not solve your persistence needs between updates as well.
In order to avoid corruption, use SQLite Transaction if you are using SQL and check this question for corruption safe strategies when dealing with files.
AFAIK there's no way to know when your app is going to be updated (you don't receive the package-related intents, because your app is not installed anymore during the update). It will simply be stopped as usual, all broadcast receivers unregistered, and updated.
What you can do, however, is add checks in your app so that when it starts it checks whether it was just updated and do whatever it is you have to do if it was. This is really simple, just store the current version of the app (which you can get via the PackageManager) in a shared preference, for example, and check the stored version against the current version every time the app starts.