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.
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
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.
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.,
bundled HTML files).
There are three main options here: raw resources, XML resources, and assets.
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
.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
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
– if you put a file named
res/raw, the identifier is
accessible in Java as
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.
If, however, your file is in an XML format, you are better served not putting
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
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.
Your third option is to package the data in the form of an asset. You can create
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
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
on the file’s contents. And, as with all types of resources, assets are read-only
One benefit of using assets over raw resources is the
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,
loadUrl("file:///android_asset/foo/index.html") will load that
HTML into the
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.
On the whole, Android just uses normal Java file I/O for local files. You
will use the same
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 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+.
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.
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.
The preview of this section was fed to a gremlin, after midnight.
The preview of this section took that left turn at Albuquerque.
The preview of this section is presently indisposed.
The preview of this section may contain nuts.
The preview of this section was eaten by a grue.
The preview of this section was whisked away by a shark-infested tornado.
The preview of this section is unavailable right now, but if you leave your name and number at the sound of the tone, it might get back to you (BEEEEEEEEEEEEP!).
The preview of this section left for Hollywood to appear in a reality TV show.
The preview of this section is in an invisible, microscopic font.
The preview of this section was last seen in the Bermuda Triangle.
The preview of this section is off trying to sweet-talk the Khaleesi into providing us with a dragon.