When should I delete temporary image files? - android

At some point in my app, I have to save some temporary image files. I've tried using file.deleteOnExit(), after some research I found out it does not ensure the file will be actually deleted. So I tried to follow one of the alternatives listed on deleteOnExit() documentation that says:
• Maintain your own set of files to delete, and process it at an appropriate point in your application's lifecycle.
I am wondering, what is this appropriate point? I've tried to delete a set of files on application.onTerminate(), but the result is the same, if the app process is killed, it'll never reach onTerminate() method.
In order to keep performance and delete temporary files safely, when (where) should I place my code to delete them?

As soon as you are sure you won't use them, but no sooner.
More seriously, you should store them in the cache directory. You can get that with Context.getCacheDir(). That way if your cleanup methods don't end up getting called, the user can delete them from the Applications menu, or the system may delete them if space is required.
You can (and should) try to delete them in onDestroy() or even onPause(), depending on your implementation, but those are also not guaranteed to be called.
You might also put a timestamp in the filename, and run a cleanup periodically with AlarmManager and BroadcastReceiver by comparing the filename (which should reflect the last time that file was accessed, ideally) with the current time, and deleting it if the difference is greater than some constant. For performance sake I would probably run this daily or a couple times a day, and also (in a background thread) when the app opens or the relevant activity starts.

Related

Trouble Conceptualizing Android File System Access

I want my app to automatically load data from a file at startup & then display a summary of this data for the user. I thought this would be simple, but...
I almost had it working, but found out that it would be tricky putting the data file on the emulated Android provided by Android Studio. So I put a basic version of the file in the package as an asset. My code checked for the file, and if not found, copies the file from assets to the phone storage. So far so good, but then I realized that this didn't really meet the requirements, because the user couldn't customize the file (through another app or by putting a new version of the file on her phone).
I found I needed to use "external" storage (which isn't really external, it's merely shared / public storage). So I used getExternalStoragePublicDirectory() to get access to the Documents folder. In the part of my code which copies the asset file to the Documents folder, I get "java.io.IOException: No such file or directory" when I try to create the target file.
This really threw me for a while, since I had preceded it with mkdirs() to ensure the folder(s) existed and I was trying to create the file in the first place.
After lots of poking around on S/O, it seems my problem may be that I don't have permissions to read / write in the Documents folder. So this is where I can't get my head around how this is supposed to work.
In my Activity's OnCreate(), I want to load the data from my file. But I need to check the permissions first. This is guaranteed to fail the first time, because the user has never granted my app this permission before.
So then I need to request the permission. But this means I can no longer load my data in the OnCreate() method, as I will get the response from the user asynchronously, in a callback method (onRequestPermissionsResult).
If the user says 'No' to my request, I need to make sure the app quits gracefully. If she says 'Yes', then... what? At this point I'm in a callback and my OnCreate() method is no longer running. How can I get back to setting up my Activity?
If I load the data file in the callback method, that only works for the initial case where the user must give permission. But after that, my app (most likely) will not lose permission, so my app will not need to ask for it. The callback will never be executed in this case. So my data file must be loaded... where?
But all of this only happens if the user is running Android 6.0 or higher. If it's an earlier version of Android, then my app can load the data in my Activity's OnCreate() method.
Oh... my head hurts!
How is all of this supposed to work? I don't need a link to the relevant methods. I need a conceptual model - a diagram would really help!
Here's the solution in a diagram: Permissions Conceptual Diagram
How can I get back to setting up my Activity?
Move the "setting up my Activity" code that depends on file I/O to a separate method. In onCreate(), check to see if you have the permission, and if you do, call that method to set up your activity. If not, call requestPermissions(). In onRequestPermissionsResult(), if you now have the permission, call that method to set up your activity.
See this sample app, which performs disk I/O from external storage using runtime permissions. The permission-handling logic is isolated in an AbstractPermissionsActivity, leaving the main activity class to handle the real business logic.
If it's an earlier version of Android, then my app can load the data in my Activity's OnCreate() method.
Well, you should be doing this disk I/O on a background thread. You can kick off that I/O from onCreate().
If you are using ContextCompat and ActivityCompat for checking and requesting permissions, respectively, your code will "do the right thing" on older devices, as those classes do the version checks for you.

Determine application first run

I want to determine whether my application being run for the first time, and so it will be hard to pass around it.
The preferences or empty file approaches are not going to work because you can simply clear the application data or delete the empty file.
Also I want to do it offline so no server checking is going to work either.
Maybe it's possible to add some code to the installation of the apk so it will only run once.
So my best bet is spawning a lot of empty files all around and hope the user won't find them, but this is pretty messy.
Has anyone ever done this somehow before? Any suggestions?
The preferences or empty file approaches are not going to work because you can simply clear the application data or delete the empty file.
One possibility is to have a BroadcastReceiver, registered in your manifest, that you do not actually use for anything. On first run of your app, disable that receiver via PackageManager and setComponentEnabledSetting(). On future runs, you can determine if that BroadcastReceiver is already disabled via PackageManager and getReceiverInfo().
If the user uninstalls and reinstalls the app, the app will return to its original state. Rooted device users can also get past this. Otherwise, this should be reasonably solid.
I know you said you dont want files, but if you create them as local internal storage then the user can not delete them as they wont have access unless it is rooted phone. Clearing data "may" delete them.
There is another solution but it is lengthy one. Use SQLite database.IT is local and I dont think it can be deleted otherwise the whole application will crash

Android SDCard I/O Managing Mount and Unmount

I know there are various version of this question asked, but I was having trouble getting a clear answer on what the best approach is for my problem.
What I am doing is I am creating a SQLite database on the SD card. I want to be able to query from it and write to it.
The question I have is what is the best way to manage when the SD card is unmounted. I am totally fine with my application closing like the stock MP3 player does. However, I want to make sure any write action to the db do not get partially done.
One thought I had is the use beginTransaction, mark it as successful, and then call end transaction. The question I have is what happens if end of transaction does not get called. Can that potentially lead to data corruption? Also, I need a little help understanding what to listen to or hook into to get notification of the sd card being unmounted.
Thanks
That is the great thing about transactions in databases - you almost never need to worry:
"All changes within a single transaction in SQLite either occur
completely or not at all, even if the act of writing the change out to
the disk is interrupted by
a program crash, an operating system crash, or a power failure."
Taken from http://www.sqlite.org/transactional.html
The disk being removed on which the database resides should (in the worst case) behave like a power failure while writing the data to the disk. The database will discard that data on next startup.
Thus, as soon as your transaction is committed using commit or end transaction and the method call executing your statement returns all data has been stored. Otherwise NO data from your transaction will have been stored - both cases leave you in a consistent state.
Beware of the only catch: You will need to make sure that all statements you need to execute together (i.e. atomically) must be within one transaction!

Detect when application is closed

I want to know when the app is closed, because I need to erase a Database when the user shutdown the app, just in the moment when the user close the app is the right moment to erase the SQLite Database, how can I detect this?
This is a flawed design idea, which reflects a misunderstanding of the system - when the process overall dies, it's dead, meaning your code is no longer running.
You can do some tracking and have the last onDestory()'d activity do the cleanup as a courtesy, but don't assume that it will always actually happen (the method is not always called). If having a stale copy is a problem, clean it up on the next run.
That said, you can try using the ndk to provide a handler for process termination signals, but still I wouldn't count on it working in all cases. The limited potential to gain any sound functionality from this would probably not justify the effort unless you are already familiar with the concepts involved.
And do not for a minute mistake cleaning up for a security mechanism, as the file is there while your app is running, and would remain if your app terminated in an unexpected way.
Supposing you don't finish() your main activity, clearing your database inside the onDestroy() method of that activity might be the closest of what you want to accomplish. As has been pointed in the comments, refer to http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle.

Implementing a robust persistent undo/redo feature

I'm writing a bitmap editor where I use the Command Pattern to represent actions that will transform the document. I keep all the commands executed so far in a list and, to implement undo, I restore the document to its initial state and then replay all but the last command.
I would like my undo/redo system to have the following feature: When the user closes the editor and returns, the document, including the available undo and redo commands, should be restored to the state it was in when the user left.
I'm implementing this for Android where your application can be given very little notice before it will be cleared from memory if e.g. the user gets a phone call. Also, some of my commands are e.g. a list of all the x,y co-ord the user painted on so these might take a few moments to save to disk.
My current idea is as follows:
When a new action is performed, the command object is added to a list S for commands that need to be saved to disk.
A background thread is used that will continually take commands from list S and save them to disk. The postfix of the filenames used will be numbered in sequence. For example, if the user filled the screen then drew 2 circles, the command files might be called FillCommand1.cmd, DrawCircleCommand2.cmd, DrawCircleCommand3.cmd.
Periodically, we save a "checkpoint" command whose purpose is to store the full document state so that, even if one of the .cmd files is corrupted, we can restore a recent version of the document.
When the user exits the app, the background thread attempts to finish up saving all the commands it can (but it might get killed).
On startup, we look for the most recent .cmd file that represents a checkpoint that we can load successfully. All the .cmd files we can load after this (i.e. some files might be corrupt) go in the redo command list, all the .cmd files we can load between the first checkpoint loaded and the oldest checkpoint we can load go in the undo list.
I want the undo limit to be about 20 or 30 commands back so I need extra logic for discarding commands, deleting .cmd files and I've got to worry about multi-threading behaviour. This system seems pretty complex and will need a lot of testing to make sure it doesn't go wrong.
Is there anything in Java or Android than can help make this easier? Am I reinventing the wheel anywhere? Maybe a database would be better?
Rather than reverting to the original then performing all actions, consider making Commands reversible. That way, if you ever decide to increase the size of your undo history, you won't be introducing the potential for lag while undoing. Alternatively, as Jared Updike notes, your application may benefit from caching render results in the near past and future.
I think you're overcomplicating things with your filesystem-based solution. If you want to maintain a backup of the entire history of current working document, you should just keep an unbuffered log open in append mode, and log actions to it. The log should be associated with the particular instance of the application and file being edited, so you don't have to worry about another thread stepping on your toes. Loading from that log should be very similar to loading from an ordinary save file. Just discarding the last-read action whenever you encounter an undo action.
Well, your code is probably imperative in nature, where the state of the application is modified in place by the user's actions. This is probably fast and straightforward. Undo is basically time-travel and if you clobber old states by modifying state in place you will have to store either recipes to recompute it in reverse, or a history that can recompute it forwards.
Like you said, you can store the actions and the initial state and play them forward (stopping at the new point in history the user selects) but that means undoing one action can cause n actions to replay. One approach is to store saved state copies in the history list so you can immediately jump to a given state. To avoid using too much RAM/storage you if your system is clever it can detect the nearest (non-null) saved state in the history and recompute those few stpes forward (assuming you have all the actions you need -- this assumes actions are small and state is large(r)) until the correct state is reached. In this manner you can start eliminating old saved states (delete or set to null) (drop the state based on a cost function inversely linear to how far back in time the state is), making undo fast for the recent past, and memory/storage efficient for ancient history. I've had success with this method.

Categories

Resources