The following is the first few sections of a chapter from The Busy Coder's Guide to Android Development, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Assets, Files, and Data Parsing

Android offers a few structured ways to store data, notably SharedPreferences and local SQLite databases. And, of course, you are welcome to store your data “in the cloud” by using an Internet-based service. We will get to all of those topics shortly.

Beyond that, though, Android allows you to work with plain old ordinary files, either ones baked into your app (“assets”) or ones on so-called internal or external storage.

To make those files work — and to consume data off of the Internet — you will likely need to employ a parser. Android ships with several choices for XML and JSON parsing, in addition to third-party libraries you can attempt to use.

This chapter focuses on assets, files, and parsers.

Packaging Files with Your App

Let’s suppose you have some static data you want to ship with the application, such as a list of words for a spell-checker. Somehow, you need to bundle that data with the application, in a way you can get at it from Java code later on, or possibly in a way you can pass to another component (e.g., WebView for bundled HTML files).

There are three main options here: raw resources, XML resources, and assets.

Raw Resources

One way to deploy a file like a spell-check catalog is to put the file in the res/raw directory, so it gets put in the Android application .apk file as part of the packaging process as a raw resource.

To access this file, you need to get yourself a Resources object. From an activity, that is as simple as calling getResources(). A Resources object offers openRawResource() to get an InputStream on the file you specify. Rather than a path, openRawResource() expects an integer identifier for the file as packaged. This works just like accessing widgets via findViewById() – if you put a file named words.xml in res/raw, the identifier is accessible in Java as R.raw.words.

Since you can only get an InputStream, you have no means of modifying this file. Hence, it is really only useful for static reference data. Moreover, since it is unchanging until the user installs an updated version of your application package, either the reference data has to be valid for the foreseeable future, or you will need to provide some means of updating the data. The simplest way to handle that is to use the reference data to bootstrap some other modifiable form of storage (e.g., a database), but this makes for two copies of the data in storage. An alternative is to keep the reference data as-is but keep modifications in a file or database, and merge them together when you need a complete picture of the information. For example, if your application ships a file of URLs, you could have a second file that tracks URLs added by the user or reference URLs that were deleted by the user.

XML Resources

If, however, your file is in an XML format, you are better served not putting it in res/raw/, but rather in res/xml/. This is a directory for XML resources – resources known to be in XML format, but without any assumptions about what that XML represents.

To access that XML, you once again get a Resources object by calling getResources() on your Activity or other Context. Then, call getXml() on the Resources object, supplying the ID value of your XML resource (e.g., R.xml.words). This will return an XmlResourceParser, which implements the XmlPullParser interface. We will discuss how to use this parser, and the performance advantage of using XML resources, later in this chapter.

As with raw resources, XML resources are read-only at runtime.

Assets

Your third option is to package the data in the form of an asset. You can create an assets/ directory in your sourceset (e.g., src/main/assets), then place whatever files you want in there. Those are accessible at runtime by calling getAssets() on your Activity or other Context, then calling open() with the path to the file (e.g., assets/foo/index.html would be retrieved via open("foo/index.html")). As with raw resources, this returns an InputStream on the file’s contents. And, as with all types of resources, assets are read-only at runtime.

One benefit of using assets over raw resources is the file:///android_asset/ Uri prefix. You can use this to load an asset into a WebView. For example, for an asset located in assets/foo/index.html within your project, calling loadUrl("file:///android_asset/foo/index.html") will load that HTML into the WebView.

Note that assets are compressed when the APK is packaged. Unfortunately, on Android 1.x/2.x, this compression mechanism has a 1MB file size limit. If you wish to package an asset that is bigger than 1MB, you either need to give it a file extension that will not be compressed (e.g., .mp3) or actually store a ZIP file of the asset (to avoid the automatic compression) and decompress it yourself at runtime, using the standard java.util.zip classes. This restriction was lifted with Android 3.0, and so if your minSdkVersion is 11 or higher, this will not be an issue for you.

Files and Android

On the whole, Android just uses normal Java file I/O for local files. You will use the same File and InputStream and OutputWriter and other classes that you have used time and again in your prior Java development work.

What is distinctive in Android is where you read and write. Akin to writing a Java Web app, you do not have read and write access to arbitrary locations. Instead, there are only a handful of directories to which you have any access, particularly when running on production hardware.

Internal vs. External

Internal storage refers to your application’s portion of the on-board, always-available flash storage. External storage refers to storage space that can be mounted by the user as a drive in Windows (or, possibly with some difficulty, as a volume in OS X or Linux).

Historically (i.e., Android 1.x/2.x), internal storage was very limited in space. That is far less of a problem on 3.0 and higher.

Similarly, external storage is not always available on Android 1.x and 2.x – if it is mounted as a drive or volume on a host desktop or notebook, your app will not have access to external storage. We will examine this limitation in a bit more detail later in this chapter. This is not usually a problem on Android 3.0+.

Standard vs. Cache

On both internal and external storage, you have the option of saving files as a cache, or on a more permanent basis. Files located in a cache directory may be deleted by the OS or third-party apps to free up storage space for the user. Files located outside of cache will remain unless manually deleted.

Yours vs. Somebody Else’s

Internal storage is on a per-application basis. Files you write to in your own internal storage cannot be read or written to by other applications… normally. Users who “root” their phones can run apps with superuser privileges and be able to access your internal storage. Most users do not root their phones, and so only your app will be able to access your internal storage files.

Files on external storage, though, are visible to all applications and the user. Anyone can read anything stored there, and any application that requests to can write or delete anything it wants.

Working with Internal Storage

The preview of this section was accidentally identified as an Android 'tasty treat' by the Cookie Monster.

Working with External Storage

The preview of this section was abducted by space aliens.

Removable Storage

The preview of this section is out seeking fame and fortune as the Dread Pirate Roberts.

Multiple User Accounts

The preview of this section apparently resembled a Pokémon.

Linux Filesystems: You Sync, You Win

The preview of this section apparently resembled a Pokémon.

StrictMode: Avoiding Janky Code

The preview of this section will not appear here for a while, due to a time machine mishap.

Files, and Your Development Machine

The preview of this section was accidentally identified as an Android 'tasty treat' by the Cookie Monster.

XML Parsing Options

The preview of this section was traded for a bag of magic beans.

JSON Parsing Options

The preview of this section was lost in the sofa cushions.

Using Files with Implicit Intents

The preview of this section left for Hollywood to appear in a reality TV show.

Visit the Trails!

The preview of this section is en route to Mars.