Book Image

Android Database Programming

By : Jason Wei
Book Image

Android Database Programming

By: Jason Wei

Overview of this book

<p>We live in an increasingly data-centric and data-driven world. On top of that we live in a very mobile-centric world with the rise of Android smart phones and tablet devices and the surge in demand for the Android platform. Along with the demand for more data, there is a demand for efficient, "snappy" applications, and so developers need to have a strong understanding of when different data storage methods are appropriate and when they are not.</p> <p>Mastering how to use these two fields to successfully create a powerful application will help you boost your knowledge and skills in this area.</p> <p>"Android Database Programming" is designed to help developers create and design data-centric mobile applications on Google’s Android platform. As the world goes increasingly mobile and as consumers’ demand for data-centric applications rises, knowing how to combine the two effectively will become an increasingly important asset to have as a developer. The book starts by looking at the various local data storage methods on Android, and finishes off by examining external databases and ways you can utilize them from within an Android application.</p> <p>This book starts by looking at local data storage methods, focusing on writing SQLite databases for your application and also looking at ways to bind these databases to the user interface. The book, through its practical approach, strives to teach you by examples. Each chapter focuses on flushing out high level design concepts, before drilling down into different code examples.&nbsp;</p> <p>As you continue you will look at external databases, primarily Google’s App Engine platform, and pull things together by helping you understand how you can request, cache, and display this data. The book then teaches the ways and techniques to utilize such external databases from within your application.</p> <p>&nbsp;</p>
Table of Contents (17 chapters)
Android Database Programming
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Using SharedPreferences


SharedPreferences is the most simple, quick, and efficient way of storing local data in your Android application. It's a framework that essentially allows you to store and associate various key-value pairs with your application (think of this as a map that comes with your application, which you can tap into at any time), and because each application is associated with its own SharedPreferences class, the data that gets stored and committed persists across all user sessions. However, because of its simple and efficient nature, SharedPreferences only allows you to save primitive data types (that is, booleans, floats, longs, ints, and strings), so keep this in mind when deciding what to store as a shared preference.

Let's look at an example of how you would access and use your application's SharedPreferences class:

public class SharedPreferencesExample extends Activity {
    private static final String MY_DB = "my_db";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
      // INSTANTIATE SHARED PREFERENCES CLASS  
        SharedPreferences sp = getSharedPreferences(MY_DB,  
         Context.MODE_PRIVATE);
      // LOAD THE EDITOR – REMEMBER TO COMMIT CHANGES!
        Editor e = sp.edit();
        e.putString("strKey", "Hello World");
        e.putBoolean("boolKey", true);
        e.commit();
        String stringValue = sp.getString("strKey", "error");
        boolean booleanValue = sp.getBoolean("boolKey", false);
        Log.i("LOG_TAG", "String value: " + stringValue);
        Log.i("LOG_TAG ", "Boolean value: " + booleanValue);
    }
}

Let's walk through what's going on in this little code snippet. First we start an Activity and in the onCreate() method, we make a request to retrieve a SharedPreferences class. The arguments for the getSharedPreferences() method are:

getSharedPreferences(String mapName, int mapMode)

Here the first argument simply specifies which shared preference mapping you want (each application can own several separate shared preference mappings, and so, just like you would specify the table name in a database, you must specify which mapping you want to retrieve). The second argument is a little more complex — in the example above, we pass in MODE_PRIVATE as the argument and this argument simply specifies the visibility of the shared preference instance you are retrieving (in this case the visibility is set to private, so that only your application can access the mappings contents). Other modes include:

  • MODE_WORLD_READABLE: Makes the visibility of your map accessible by other applications, though contents can only be read

  • MODE_WORD_WRITEABLE: Makes the visibility of your map accessible by other applications for both reading and writing

  • MODE_MULTI_PROCESS: This mode, available since API Level 11, allows you to modify your map by multiple processes which may be writing to the same shared preference instance

Now, once we have our shared preference object, we can immediately start retrieving contents by its various get() methods — for instance, the getString() and getBoolean() methods we saw earlier. These get() methods will typically take two parameters: the first being the key, and the second being the default value if the given key is not found. Taking the previous example, we have:

String stringValue = sp.getString("strKey", "error");
boolean booleanValue = sp.getBoolean("boolKey", false);

And so, in the first case, we're trying to retrieve the string value associated with the key strKey, and defaulting to the string error if no such key is found. Likewise, in the second case, we're trying to retrieve a boolean value associated with the key boolKey, and defaulting to the boolean false if no such key is found.

However, if you want to edit contents or add new content, then you'll have to retrieve the Editor object that each shared preference instance contains. This Editor object contains all of the put() methods which allow you to pass a key along with its associated value (just like you would for a standard Map object) — the only caveat is that after you add or update the content of your shared preference, you need to call the Editor object's commit() method to save down those changes. Furthermore, again, just like a standard Map object, the Editor class also contains remove() and clear() methods for you to freely manipulate the contents of your shared preference.

One last thing to note before we move on to typical use cases of SharedPreferences is that if you decide to set the visibility of your shared preference instance to MODE_WORLD_WRITEABLE, then you are potentially exposing yourself to various security breaches by malicious external applications. As a result, in practice, this mode is not recommended. However, the desire to share information locally between two applications is still one that many developers face, and so a method for doing so was developed that simply involves setting an android:sharedUserId in your application's manifest files.

How this works is that each application, when signed and exported, is given an auto-generated application ID. However, if you explicitly set this ID in the application's manifest file, then, assuming two applications are signed with the same key, they will be able to freely access each other's data without having to expose their data to the rest of the applications on a user's phone. In other words, by setting the same ID for two applications, those two and only those two applications will be able to accss each other's data.

Common use cases for SharedPreferences

Now that we know how to instantiate and edit a shared preference object, it's important to think about some typical use cases for this type of data storage. And so, following are a couple of examples, illustrating what kinds of small, primitive key-value data pairs applications tend to like to save.

Checking if it's the user's first time visit to your application

For many applications, if this is the user's first visit, then they will want to display some kind of instructions/tutorials activity or a splash screen activity:

public class SharedPreferencesExample2 extends Activity {
    private static final String MY_DB = "my_db";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        SharedPreferences sp = getSharedPreferences(MY_DB, 
         Context.MODE_PRIVATE);
        /**
         * CHECK IF THIS IS USER'S FIRST VISIT
         */
        boolean hasVisited = sp.getBoolean("hasVisited", 
         false);
        if (!hasVisited) {
            // ...
            // SHOW SPLASH ACTIVITY, LOGIN ACTIVITY, ETC
            // ...
            // DON'T FORGET TO COMMIT THE CHANGE!
            Editor e = sp.edit();
            e.putBoolean("hasVisited", true);
            e.commit();
        }
  }
}

Checking when the application last updated itself

Many applications will have some kind of caching, or syncing, feature built-in, which will require regular updating. By saving the last update time, we can quickly check to see how much time has elapsed, and decide whether or not an update/sync needs to occur:

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

/**
* CHECK LAST UPDATE TIME
*/
long lastUpdateTime = sp.getLong("lastUpdateKey", 0L);
long timeElapsed = System.currentTimeMillis() - 
lastUpdateTime;
// YOUR UPDATE FREQUENCY HERE
final long UPDATE_FREQ = 1000 * 60 * 60 * 24;
if (timeElapsed > UPDATE_FREQ) {
// ...
// PERFORM NECESSARY UPDATES
// ...
}
// STORE LATEST UPDATE TIME
Editor e = sp.edit();
e.putLong("lastUpdateKey", System.currentTimeMillis());
e.commit();

Remembering what the user's login username was

Many applications will allow the user to remember their username (as well as other login-oriented fields such as PINs, phone numbers, and so on) and a shared preference is a great way to store a simple primitive string ID:

/**
* CACHE USER NAME AS STRING
*/
// TYPICALLY YOU WILL HAVE AN EDIT TEXT VIEW
// WHERE THE USER ENTERS THEIR USERNAME
EditText userNameLoginText = (EditText) 
findViewById(R.id.login_editText);
String userName = 
 userNameLoginText.getText().toString();
Editor e = sp.edit();
e.putString("userNameCache", userName);
e.commit();

Remembering an application's state

For many applications, the functionality of the application will change depending on the application's state, typically set by the user. Consider a phone ringer application — if the user specifies that no functionality should occur if the phone is in silent mode, then this is probably an important state to remember:

/**
* REMEBERING A CERTAIN STATE
*/
boolean isSilentMode = sp.getBoolean("isSilentRinger", 
 false);
if (isSilentMode) {
// ...
// TURN OFF APPLICATION
// ...
}

Caching a user's location

Any location-based application will often want to cache the user's last location for a number of reasons (perhaps the user has turned off GPS, or has a weak signal, and so on). This can be easily done by converting the latitude and longitude of the user to floats and then storing those floats in a shared preference instance:

/**
* CACHING A LOCATION
*/
// INSTANTIATE LOCATION MANAGER
LocationManager locationManager = (LocationManager) 
 this.getSystemService(Context.LOCATION_SERVICE);
// ...
// IGNORE LOCATION LISTENERS FOR NOW
// ...
Location lastKnownLocation = 
 locationManager.getLastKnownLocation
 (LocationManager.NETWORK_PROVIDER);
float lat = (float) lastKnownLocation.getLatitude();
float lon = (float) lastKnownLocation.getLongitude();
Editor e = sp.edit();
e.putFloat("latitudeCache", lat);
e.putFloat("longitudeCache", lon);
e.commit();

With the latest version of Android (API Level 11), there is also a new getStringSet() method which allows you to set and retrieve a set of string objects for a given associated key. Here's how it looks in action:

Set<String> values = new HashSet<String>();
values.add("Hello");
values.add("World");
Editor e = sp.edit();
e.putStringSet("strSetKey", values);
e.commit();
Set<String> ret = sp.getStringSet(values, new HashSet<String>());
for(String r : ret) {
    Log.i("SharedPreferencesExample", "Retrieved vals: " + r);
}

Use cases for this are plenty — but for now let's move on.