Published: 17 Aug 2011
By: Dino Esposito

In this article, I'll dissect the code of a realistic application - a waterpolo score manager - to show how to save and resume the status of a game using both the internal storage and SD card.

Contents [hide]

The Android for .NET Developers Series

  • Part 1 Starting with this article, I'll discuss what you need to know to approach Android programming without any aid from your .NET expertise.
  • Part 2 In this article, we'll go through an Android application that accepts input from the user and handles user's clicking.
  • Part 3 In this article, you will learn how to build the user interface.
  • Part 4 In this article, I'll be delving deep into menus and dialog boxes in Android for .NET, and discuss a few very common (and frequently used) types of menus and dialogs.
  • Part 5 In this article, Dino Esposito focuses on the options that the Android SDK offers for local storage.
  • Part 6 In this article, Dino Esposito shows how to build settings dialog boxes using a built-in feature of Android for .NET.
  • Part 7 In this article, I'll dissect the code of a realistic application - a waterpolo score manager - to show how to save and resume the status of a game using both the internal storage and SD card.
  • Part 8 In this article, I'll focus on the execution of common tasks from within an Android application. I'll build the skeleton of an application that takes a photo and emails to the specified address. For both tasks I'll use native Android components.
  • Part 9 In this article, I'll discuss how to arrange an Android view where the dominant element is the list. I'll start with a plain list of strings and then improve up to populating a listview with downloaded content arranged using a custom layout.
  • Part 10 In this article, I'll discuss the features and capabilities required by an Android application to talk with Twitter. In particular, I'll focus on authentication and updates.
  • Introduction

    Any serious mobile application will use the local storage to persist as much data as possible thus enabling offline working and occasionally connected scenarios. The extent at which this is really possible varies with the goals of the application. Nearly any application, however, can take some advantage of some working data saved locally. In general, an Android mobile device offers two options for storage - phone internal storage and external SD cards. The internal phone storage is limited and not expandable; an SD card can be replaced as needed. This is the common scenario you face with Android; in the iPhone space, for example, external cards are not supported. In Windows Phone 7, only a few devices allow you to add an external card which can't be ported to other types of phone after use.

    This distinction between internal and external storage is important because in Android you need to use a slightly different API to read and write files in both locations. More, the internal storage that is left to user applications is tiny space in the order of 100MB for most devices. (I have an HTC Desire, but I've heard similar stories for devices of the same class.) In this article, I'll dissect the code of a realistic application - a waterpolo score manager - to show how to save and resume the status of a game using both the internal storage and SD card.

    Creating Files in the Internal Storage

    Each Android application gains access to the internal storage through a bunch of functions exposed as part of the application context. The storage is generally considered private of the application and will be removed when you uninstall the application or when you choose to clear the data of the application through the interface of the phone's maintenance application. The Android API for preferences saves data to the internal storage and this data is removed when you clean/uninstall the application.

    The simplest way to create a file in the private area is shown below:

    The openFileOutput function is exposed out of the Context class. If you're calling this code from within an activity object then you're OK as the Activity class inherits from Context. More likely, instead, you want to move this code to a distinct helper class. In this case, the method that creates the file must receive a Context argument:

    The code creates a new file with the specified name under a specific path. The usual path is:

    As you can see, the files are grouped under an application specific folder - in this case, the folder com.expoware.waterpolo as the application's namespace. In your code, however, you're not expected to know the details of the path. Calling the built-in openFileOutput function does the trick for you.

    In the example above, the content of the file is given by an array of bytes. This may or may not be a format easy to work with. In the sample application that inspired this article I use a class to store the details of the game and use Java serialization to persist an instance of the class. In this case, having a byte oriented programming interface is more than acceptable. The same can be said if your application deals with audio or image files to be created from native streams.

    Java (and Android as well) supports writer and readers classes that you may know already very well from .NET. If you want to write (or read) bits and pieces of the file content through primitive types you do as follows:

    It should be noted that Java forces you to try/catch calls that explicitly declare exceptions. This is not the case in .NET, but may be surprising at first. If you get a run time error that complains about not handling an exception, well, that's just the rule.

    Creating Files on a Different Directory

    The openFileOutput function is limited to the root directory of the space reserved to your application. What if you want to save a file to a specific folder? In this case, you use an API that's similar to the one you need to use to write to the SD card. Here's the full code.

    The first thing to do is arranging the full path name you want to address. This is necessary as you want to take control over the path. The function getFilesDir returns the root directory of the application's storage space: the /data/data/[app]/files folder we met earlier transparently managed by the openFileOutput function. The File class wraps a file or a directory; the following code creates a wrapper for the matches directory under the root:

    You might want to ensure that the full directory path exists - that's the purpose of calling mkdirs. If something went wrong, the can canWrite function on the File class returns false. If not, you can proceed with actual writing. You create a new File object to represent the file you intend to create and just write it. You can use the FileWriter class as an alternate approach to streams. Like in .NET, if your data doesn't come in the bytearray form there's no need to deal with cumbersome streams - a reader/writer API is easier and more effective.

    So in the end, the openFileOutput function is a shortcut that's easy to use, but a bit limited functionally speaking. If that doesn't work your intended purposes, use FileWriter and use the File class to find the target location on the phone storage.

    Reading File Content

    The API for reading some file content is specular. You can use readers or input streams, and you use the same API to locate source files. Here's how to read a serialized class from a binary file.

    Once you know the location of the file you want to read, you get its length and allocate a large enough array of bytes. Next, you open the file (in the code snippet I'm using openFileInput) and fill the bytearray with content. Let's find out more object serialization.

    Serializing Objects

    When you need to save a collection of data, the best option is stuffing data into a class and serialize the class using the ObjectOutputStream class. For my convenience, I created an ObjectFormatter class with two façade methods - Serialize and Deserialize. Here's the code.

    As you can see, the Serialize method gets an object and returns an array of bytes; the Deserialize method does the reverse. The return value of Deserialize must be cast to the correct type in order to be really usable.

    Getting a List of Existing Files

    My sample waterpolo application offers a Save Match menu item (see Figure 1) through which users save the current score to a file. At some point, they might want to reload that content to resume the match after an interval or to share the score with friends once the game is finished. (This is just what most parents love to do when their kids win the game.)

    Figure 1: Saving a match

    Saving a match

    The idea is getting the list of files from storage, populate a pick list and let users choose the match they want to load to perform further operations. Here's the only code you need to get the list of files in the internal storage:

    The fileList function is defined on the activity and comes with a bunch of companion functions that also allow a filtered search. Once you have the list of files creating a popup pick list is a child's game:

    OK, I'll be honest. This is not exactly what I'd a child's game. It's rather ugly code; yet the code to write. The good news is that you can reuse it over and over again without much extra thinking. In this regard, it is simple code.

    The setItems method loads the elements of the list and the event handler to invoke when one is clicked. Figure 2 shows the final results.

    Figure 2: Picking a match from the list of saved matches

    Picking a match from the list of saved matches

    The Device SD Card

    When the amount of data to save grows big, you might want to consider saving data to the SD card to preserve primary storage for applications. On some devices, however, you're allowed to move applications to the SD at any time; and you just do so when you run short of space. Writing to the SD card requires a special permission. You declare your intention about the SD card in the application's manifest file:

    The key line is the <uses-permission> element: everything else is just the default content of any manifest file. To create a file, you use an API nearly identical to the one discussed for custom folders:

    The key difference is in the function you use to retrieve the root path of the SD. You use the following expression:

    This returns a path similar to /mnt/sdcard. Starting from here you can create your custom folders and fill them up. None of this content will be removed when you uninstall the application. Clearing your stuff is your responsibility.

    Writing to the SD card is not possible all the time. For example, when the device is connected to a PC the content of the SD card is hidden. For this reason, it is recommended that you always call getExternalStorageState before you perform any operation on the external storage. The function will check whether the media is available. Check http://goo.gl/lVuk for the details of the various states in which the card can be.

    Finally, how to work with the SD card within the emulator? It requires a few tricks. First off, you create an ISO image simulating the card. The Android SDK provides an apt tool you command as below:

    You can specify the size and the file name. The file can be moved around and can be viewed through Winzip or any other tool that handles ISO files. If you use IntelliJ or Eclipse, you have a visual guide to mapping the fake SD card to the emulator. You must create the ISO image yourself.

    The Android for .NET Developers Series

  • Part 1 Starting with this article, I'll discuss what you need to know to approach Android programming without any aid from your .NET expertise.
  • Part 2 In this article, we'll go through an Android application that accepts input from the user and handles user's clicking.
  • Part 3 In this article, you will learn how to build the user interface.
  • Part 4 In this article, I'll be delving deep into menus and dialog boxes in Android for .NET, and discuss a few very common (and frequently used) types of menus and dialogs.
  • Part 5 In this article, Dino Esposito focuses on the options that the Android SDK offers for local storage.
  • Part 6 In this article, Dino Esposito shows how to build settings dialog boxes using a built-in feature of Android for .NET.
  • Part 7 In this article, I'll dissect the code of a realistic application - a waterpolo score manager - to show how to save and resume the status of a game using both the internal storage and SD card.
  • Part 8 In this article, I'll focus on the execution of common tasks from within an Android application. I'll build the skeleton of an application that takes a photo and emails to the specified address. For both tasks I'll use native Android components.
  • Part 9 In this article, I'll discuss how to arrange an Android view where the dominant element is the list. I'll start with a plain list of strings and then improve up to populating a listview with downloaded content arranged using a custom layout.
  • Part 10 In this article, I'll discuss the features and capabilities required by an Android application to talk with Twitter. In particular, I'll focus on authentication and updates.
  • <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Dino Esposito

    Dino Esposito is one of the world's authorities on Web technology and software architecture. Dino published an array of books, most of which are considered state-of-the-art in their respective areas. His most recent books are “Microsoft ® .NET: Architecting Applications for the Enterprise” and “...

    This author has published 53 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    Developing a Hello World Java Application and Deploying it in Windows Azure - Part I
    This article demonstrates how to install Windows Azure Plugin for Eclipse, create a Hello World appl...
    Android for .NET Developers - Building a Twitter Client
    In this article, I'll discuss the features and capabilities required by an Android application to ta...
    Ref and Out (The Inside Story)
    Knowing the power of ref and out, a developer will certainly make full use of this feature of parame...
    Developing a Hello World Java Application and Deploying it in Windows Azure - Part II
    In this article we will see the steps involved in deploying the WAR created in the first part of thi...
    Android for .NET Developers - Using Web Views
    In this article, I'll show a native app that contains a web-based view. The great news is that HTML ...

    You might also be interested in the following related blog posts


    Announcing Microsoft Ajax Library (Preview 6) and the Microsoft Ajax Minifier read more
    Hey, nice package! read more
    Extending SharePoint Site Provisioning using Site Definition ProvisionData read more
    FileSystemWatcher Events and incomplete file errors read more
    Team Foundation Server and the missing file sharing (Part 2) read more
    Adding Breadcrumb Navigation for SharePoint Application Pages read more
    Tool of the Day: WSPBuilder for SharePoint read more
    Retrieve File Contents using SQL Server 2005 SQL CLR read more
    Sharing Entity Framwork models between projects (or teams) when developing read more
    Where did my MSDN go? read more
    Top
     
     
     

    Please login to rate or to leave a comment.

    Free Agile Project Management Tool from Telerik
    TeamPulse Community Edition helps your team effectively capture requirements, manage project plans, assign and track work, and most importantly, be continually connected with each other.