Android Persistence: Internal Storage

As Android developers, we have a few options for persisting our application data across runs:

  • SQLite database
  • external storage on the SD card, or through networking
  • SharedPreferences (see previous article)
  • or we can use the phone’s internal file system, and store data in files which are, by default, only visible to our application.

Why would we want to use internal files to persist data? Because of the following considerations:

  1. If a SQLite database would be overkill for our use case, and we, as always, are looking for the simplest solution that works
  2. If SharedPreferences doesn’t  meet our functional requirements. For example, we might need to persist entire objects, not just primitives. or our application is using multiple processes (not supported by the SharedPreferences API at this time)
  3. If external storage on the SD card does not meet our security requirements, since all other applications can read the files stored on the SD card. Besides the user could remove those files accidentally.
  4. If external Storage on some Web server is not an option, because we want our application to be able to access the persisted data even in the absence of internet connection.

Using an internal file to persist data is pretty simple: we save and retrieve data using the Android.content.Context ‘s openFileOutput() and openFileInput(), which return a java.io.FileOutputStream and a java.io.FileInputStream respectively. From there, it’s just our typical Java file I/O operations.

String FILENAME = "xfile";

// saving into file
FileOutputStream fos = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
// write I/O using write() and close()

//...
// retrieving from file
FileInputStream fis = context.openFileInput(FILENAME);
// read I/O using read() and close()

Context.MODE_PRIVATE means our internal files are only visible to us. There are other modes, like  MODE_APPEND, MODE_WORLD_READABLE and MODE_WORLD_WRITABLE which are self-explanatory. We want to use MODE_APPEND when we need to add data to the end of the file, otherwise we will overwrite the file every time we write to it.

But where exactly is that internal file saved? If we really want to know, its absolute path is returned by the Context’s getFilesDir() call. Another method of Context, fileList(), will return an array of all the files saved by our application.

These internal files are of course deleted once our application itself  is removed by the user. But just in case we would like to delete an internal  file ourselves in the course of our application workflow, there’s always the Context’s deleteFile() method for that purpose.

As we can see, the internal file storage API is provided by the  Context class, which basically provides access to our application environment.
.
This article is also available at JavaLobby.

Advertisements

, ,

  1. #1 by drinking app on April 18, 2012 - 6:07 pm

    Nice post. I learn something new and challenging on sites I stumbleupon everyday. It’s always exciting to read through articles from other writers and practice a little something from their sites.

  2. #2 by dila on June 6, 2012 - 4:53 am

    Nice Post
    Thanks

  3. #3 by Peter on October 3, 2012 - 2:30 am

    Is there a way to keep this internal storage permanent and ouf of the hands of “cache cleaners”? I’ve stored files for my app in what I thought was “persistent” storage. However, many users are complaining that they are losing the data and this happens if they run cache cleaners.

    • #4 by Tony S. on October 3, 2012 - 9:44 am

      Are you using MODE_WORLD_WRITEABLE instead of MODE_PRIVATE?

      Permanent internal storage and cache are different directories, and you can verify that easily. On my phone:

      getApplicationContext().getFilesDir().getAbsolutePath() returns /data/data/app_package/files

      …while

      getApplicationContext().getCacheDir().getAbsolutePath() returns /data/data/app_package/cache

      Assuming that the ‘cache cleaners’ work as intended, It is also possible that users run them while your application is in the middle of I/O operations. by pausing or stopping a running activity. In that case, you should save the data also in lifecycle methods: onPause() or onStop().

      • #5 by Peter on October 3, 2012 - 12:34 pm

        Thanks very much for your reply. I can confirm I am using MODE_PRIVATE and that the files are being stored in /data/data/your_app_package/files as I have logging turned on and write the folder that the day was saved to. I had been storing them in the Cache folder. However, a recent change in my app moved them to a folder within /data/data/your_app_package/. The data is saved after each major update, and so it would have to be a huge coincidence that the file is corrupted each day as for some users this is an issue that happens daily, if not several times per day.

        What you are saying though, is that if the app is putting the data in this folder, it should not be removed by the system. Therefore, I can let the users know that they need to look to their cache cleaners for a solution.

        Additional question…since the data I am storing is in the private app area, and these phones are not rooted, how are these applications even getting access to the folder /data/data/your_app_package/? I thought this data was protected from other apps?

        Thanks again for your help and attention to my questions!

      • #6 by Tony S. on October 3, 2012 - 1:23 pm

        The /data/data/your.package.name/ directory is where sub-folders for the other internal storage options would be if you used them, like shared_prefs/ for SharedPreferences and databases/ for SQL lite storage . I suggest you install a cache cleaner yourself and experiment to reproduce the issue, and determine what gets cleaned up.

        If the phones are not rooted, and they’re getting access to private files anyway, the API is not working as intended. The only way those files would get removed is when the app is uninstalled.

  1. Android Persistence: External Storage (SD Card) « Tony's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: