I have an android app that needs to store critical information coming from a sensor. The sensor updates data every 5 ms. I need to persist each of these data points on internal memory in text files.
In the current scenario, I am collecting data points for 2 seconds in memory and then writing to the file at the end of 2 seconds to save battery life. However, under situations where the app crashes, I am loosing the critical data points.
Does anyone have any suggestions on how to handle this?
Is it a good idea to write the data point to the file every 5ms. Would this significantly reduce the battery life and increase the load on the CPU? If anyone has come across a similar situation, can you please share how you resolved the issue?
I would suggest you to study the reason of your app crash. If your app is crashing because of internal exceptions there is a better way of dealing with this thing.
Write a good exception management and use this blocks to write data to internal memory whenever there is an exception generated. Re-start the app after the data has been successfully written.
It you app is crashing because of external reasons and you are unable to catch exceptions, you have to think of some other way.
As your App is critical, I would look into setting up a DefaultUncaughtExceptionHandler by calling Thread.setDefaultUncaughtExceptionHandler in your Application class. This way in the handler, you can write all unsaved data, AND you can restart the app for continued handling of your critical data. I would put some seconds counter in there, to prevent an infinite loop of crashes. The Open Source ACRA library uses Thread.setDefaultUncaughtExceptionHandler, so you may get some idea from there on how to use it.
An additional idea is to write the data using a service in a separate process, search for "Remote Service". This way, even if the app crashes, the service will still be alive. You will have to setup some functionality on how to share the data between the app and the service. If the app is really critical, I would setup 2 remote services, one that gets the info from the sensor (and caches it as a backup until confirmed that it's written), and one that caches the data and writes it every few seconds. Each service should also have a DefaultUncaughtExceptionHandler as above. This is in addition to the actual app, that will have the user interface. Though it is a little waste of resources, but for critical data it is not wasted.
i donot think there's a good method. What more important is to avoid crash maybe
Instead of writing to a file every 5 ms, which will be a costly operation, you can save data to SharedPreferences every 5 ms and every 2 sec, save the data from SharedPreferences to a file. SharedPreferences content won't be deleted even if app crashes and hence you will not have any data loss.
Related
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.
As far as I can read, Android may kill my process at any time 1.
One might interpret the article [1] such that, at any point, a process must be able to survive a crash. How is that handled? Are there any guarantees of any methods being called if a process is killed this way? The article* doesn't mention it.
My question is, how do you guarantee that a force-killed process resumes in some sane way on next start? The only state my process has (assuming no guarantees are made for methods being called when process is killed) is the state in persistent storage (a DB or elsewhere) and this is likely to be incomplete if process is force-killed.
Concrete example: Let's say I ask a Service to perform some work. This work is not something like playing a music file. It is work that can be considered "done" at some point (e.g. sending data to the web). If my Service gets killed, say after 50% of the work is done, how would my app know if the work was successful? I could have a flag in persistent storage saying "done", but even then, Android might kill my Service after I send the last byte and before I set the flag.
Is there any common way of handling this? My Service could, when restarted, negotiate with the web server to see if the file was transferred, but it quickly gets really complicated and I don't think it would really solve the problem.
[Edit 1 start]
I am aware of the following text [1] but that does not solve the problem for services, "This last state is generated each time the user leaves that part of the application, not when it is killed"
[Edit 1 end]
[Edit 2 start]
I found something really interesting. An apparent inconsistency in the Android documentation related to this. Please see my new question at 2
[Edit 2 end]
[Edit 3 start]
The "apparent inconsistency" has been resolved. It was due to me not being precise about "app"/"process"/"activity" terms. This question still stands, though.
[Edit 3 end]
Are there any guarantees of any methods being called if a process is killed this way?
Nothing is called on your app when your process is terminated.
how do you guarantee that a force-killed process resumes in some sane way on next start?
That cannot be answered in the abstract.
The only state my process has (assuming no guarantees are made for methods being called when process is killed) is the state in persistent storage (a DB or elsewhere) and this is likely to be incomplete if process is force-killed.
You should be updating your local persistent store when the data changes. Hence, your persistent store is likely to be up to date when your process is terminated. An in-memory cache should be treated as a read cache, not a write cache.
It is work that can be considered "done" at some point (e.g. sending data to the web). If my Service gets killed, say after 50% of the work is done, how would my app know if the work was successful?
It would have to negotiate with the Web server to determine what was and was not successfully uploaded.
Is there any common way of handling this?
There are various approaches for trying to maintain "transactional integrity", particularly for long-running operations where process termination poses a greater issue. None of those are unique to Android, as this has been a problem in computers for decades. Most boil down to "check what succeeded, and re-try what didn't". How complicated this is depends entirely on the nature of the data you are trying to update and the available means for updating 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.
Basically I have an app that would require things(around 20 index files) to be loaded at the start of the app in-order to do some instant-searching later in the app. Although all in all, the index files totally is only several hundred K, as decompression has to be done, the loading actually takes a while. So I am wondering if it is possible to keep it in memory by running service? I wrote a local service within the same package with my app. And when I force closed my app, my service closes too. Should I be using a remote service? if so what I have to do is when I open up my app, it should be able to get 1 int[] and 1 ArrayList from the service, is this doable? or are there any other better options? Thanks a lot
Keep in mind - you're developing for a mobile phone. Memory is limited. Your app will not be the only app the user will be running. Trying to hog memory persistently for the benefit of your own app is bad practice. The user will not want to have your service running all the time.
Sure, the operating system will eventually kick your service out of the window if memory gets tight, but it's better practice to not use a service to store data. Use a separate thread on startup and decompress the data.
You could consider writing the decompressed index file to external storage, or compressing it in chunks so that you can get by without having to decompress the entire thing.
If you really think this is an important feature for your app, make it optional in the settings and add a service (possibly even using a broadcast receiver on boot if your app is so important to the user) to load and decompress the data. But I would really recommend against having a service for storage, if that's what you're planning to use.
Lets say I have a Service S and Activity A. S downloads data for A (or handles some long running work, whatever), but A is not always present. I don't want S to hang around when it's job queue is empty: S should post the results of the finished works to some kind of a mailbox for A, so A can pull the messages when it comes back again.
Can this be achieved without using SQLite of file storage for the implementation of the mailbox? I'd prefer some faster mechanism, write operations tend to be quite slow on a device. I thought about using a simple static list inside the ApplicationContext, but afaik relying on the ApplicationContext results a risky/fragile solution.
Could anyone recommend a pattern for this problem?
Can this be achieved without using SQLite of file storage for the implementation of the mailbox?
Not reliably. Either it's a file, or it might be nuked before A comes back again. Remember that your process -- where all your static data members and the Application object reside -- does not live forever. Once S shuts down (which is a good thing, thanks!), Android is welcome to terminate the process, taking your "mailbox" with you if it is solely in RAM.
You could persist it to disk yet keep a singleton or something around as a cache, so if A returns quickly you can skip some of the I/O. Or, if it does not really matter much if the messages exist for A, you could keep them in RAM and simply shrug your shoulders if the process gets terminated first.