BlackBerry Persistent Store BLACKBERRY

The Persistent Store enables you to save objects to the device’s flash memory. Because it doesn’t support saving to the SD card, it’s not a good idea to use it to store documents or anything else that can run up to large amounts of storage space. Most modern devices have at least 128 MB of flash memory onboard and typically, a significant percentage of that is free even after taking into account space used by the OS, email, and other data. This means you don’t have to knock yourself out trying to save space while writing typical application data like user settings; however, if you need to manage many high-resolution photos, audio, or video files, the FileConnection API is probably a better choice, and is covered later in this chapter.

There are only two classes you really need to be familiar with to use the Persistent Store:

Persistent Store Keys

Persistent Store manages a list of keys (long values) and objects (instances of Persistent Object). The list of keys is global across all applications on the device. Unfortunately, you don’t know ahead of time which keys are in use by other applications; but, in practice, the keyspace is so large that conflicts never occur. Fortunately, BlackBerry JDE and JDE Plug-in for Eclipse both offer a convenient shortcut for generating a long value for use as a key. Simply type some text into the editor, select it,and right-click. A menu item called Convert String to Long (for the Eclipse plug-in—see Figure) or Convert [Selected Text] to long (for the JDE—see Figure) and a new long value is generated based on a hash of the selected text.

Creating a long value for a Persistent Store key with the Eclipse plug-in

Creating a long value for a Persistent Store key with the Eclipse plug-in

Creating a long value for a Persistent Store key with the JDE

Persistent Objects

Using the PersistentStore.getPersistentObject method returns an instance of Persistent Object, even if the key hasn’t ever been used before. This is important.You always get back a PersistentObject, but the content of that object might be null. This means either that nothing has been saved with that key or it was deleted:

The contents of the PersistentObject are accessed through the getContents method.Again, this method might return null:

To set or replace the contents of the PersistentObject, use the setContents method:

Setting the contents, however, does not mean the object has been persisted. For that, you need to call the commit method:


One final note: the PersistentObject maintains a reference to its contents. To change the data in the PersistentObject,, you just need to modify that instance and call persistent Object.commit; you do not need to call setContents again, unless you want an entirely different object to be associated with the given persistent key:

// This will persist MyKey and New Value
// no need to call persistentObject.setContents
hashtable.put("MyKey", "New Value");

What Can You Persist?

The Persistent Store obviously can directly persist only objects, not primitive types. You can’t directly persist an int, for example, but you can wrap the int in an Integer object and persist that:

persistentObject.setContents(new Integer(1234));

Generally, any object that you pass into setContents must implement the net. rim. device. api. util. Persistable interface.This interface contains no methods; it’s just a marker for the BlackBerry OS. A lot of the built-in classes on the BlackBerry implement this interface. See the Javadocs for Persistable for a list.

In addition to these, a few of the basic Java classes are also allowed, even though they don’t explicitly implement Persistable.These additional allowed persistable classes are:

Arrays of primitive types are also implicitly persistable, as are arrays of other persistable types. So, you can persist byte[], char[], int[],String[], Vector[], and so on. Note that persistence saves the entire object, including all objects it references. This means that if your object references other objects, those objects must be persistable, too. In the previous example, we could persist the hashtable after we added a new keyvalue pair because the key and value were both strings, and String is persistable.However, the following would not be allowed:

But if MyClass implements Persistable, everything will work:

That’s enough of the theory to get us started. We’ll touch on a couple of other details later, but for now let’s put this knowledge to work.

The Persistable Application

Create a new BlackBerry application project called Persistable. The main screen will have a few controls on it, so we can demonstrate persistence of different data types. To save time, here’s the code for both classes:

We intentionally kept this simple. The application will save data when you exit and load that data into the appropriate UI components when you start the application. Note that we added a bunch of imports to PersistenceScreen here to save time later on.

The Persistent Object

We need to have the persistent object available to load and save data. We’ll make it an instance variable of PersistenceScreen:

Now let’s define the key. Right under the PersistentObject declaration, type com. thinking blackberry. persistence. PersistenceScreen,”and then highlight it and select Convert String to Long:

You should get the same long value as above if you started with the same string (don’t worry if you didn't; it’s not important for this exercise. As long as you have some value,the application will still work).Finally, add the following to make it a static final long variable:

##strat Spublic class PersistenceScreen extends MainScreen { PersistentObject persistentObject; static final long KEY = 0x9df9f961bc6d6baL;

Now add the following line to the constructor to initialize the object:

persistentObject = PersistentStore.getPersistentObject(KEY);

Loading the Data

Loading is easy in this case. We’ll store a string directly into the contents of the Persistent Object so we’ll check to see whether a string was set, and if so, update the edit field:

##start if (persistentObject.getContents() != null) { editField.setText((String)persistentObject.getContents()); }

The Save Method

We’ll start by saving the data. This introduces another new UI concept; the screen’s save method. Every screen on the BlackBerry keeps track of whether its controls have been modified since it was displayed. If they have, it displays a Save/Discard/Cancel prompt to the user. If the user chooses “Save,” the save method is called. By overriding that method, you can save your data when the screen is closed.Add the following code to PersistenceScreen:

##start public void save() throws IOException { persistentObject.setContents(editField.getText()); persistentObject.commit(); }

That’s all you have to do! Now go ahead and run the application. The first time, you’ll see the edit field is empty.

Persistence application before entering any data

Persistence application before entering any data

Now enter some text into the edit field and click the Escape key to exit the application. The Save prompt displays as shown in Figure.

The Save prompt

The Save prompt

Select Save, and the application exits. Now when you restart the application, the text displays in the edit field just as you entered it.

We've successfully saved and loaded data!

We've successfully saved and loaded data!

More Advanced Persistence

The initial example was just to give you an idea of how easy persistence can be. We’ll now modify the application to do something that might be a little more applicable in a real-world application. The Persistent Store’s use of long values for keys, and the method of wrapping each stored object in a PersistentObject makes it easy to store individual objects, but what if (as in most applications) you need to store a lot of different pieces of data? You can use a different long key for each one, but that rapidly gets unmanageable. The solution is to store a java.util.Hashtable in the PersistentObject, and then store each piece of data within that hashtable.A Hashtable stores a set of key-value pairs, and as long as all the keys and all the values are persistable objects, you can persist the hashtable itself.

Modifying the UI

To give us some more data to store, we’ll add a few fields to the PersistenceScreen.Add the following to the top of the PersistenceScreen class:

##start CheckboxField checkboxField; NumericChoiceField numericChoiceField; DateField dateField;

And the following lines to the constructor:

##start checkboxField = new CheckboxField("Boolean data", false); numericChoiceField = new NumericChoiceField("Numeric data:", 1, 10, 1); dateField = new DateField("Date:", System.currentTimeMillis(), DateField.DATE); add(checkboxField); add(numericChoiceField); add(dateField);

NumericChoiceField basically acts the same as the ObjectChoiceField you saw earlier, but contains only integer values and has a couple of methods to make getting and setting the values as ints easy. DateField naturally enough displays a date and time as represented in Java as a long value.

Using a Hashtable

We’re going to make the persistent object use a Hashtable to store its contents, instead of storing a String. Add a declaration for the Hashtable to the top of PersistenceScreen:

public class PersistenceScreen extends MainScreen {
Hashtable persistentHashtable;

The idea in the constructor is to create the Hashtable if this is the first time using the Persistent Store, or load it if not. Change the initialization code for the PersistentObject to the following:

##start if (persistentObject.getContents() == null) { persistentHashtable = new Hashtable(); persistentObject.setContents(persistentHashtable); } else { persistentHashtable = (Hashtable)persistentObject.getContents(); }

Loading and Saving the Data

With the hashtable initialized, add the following lines to the end of the PersistenceScreen constructor to load the data:

##start if (persistentHashtable.containsKey("EditData")) { editField.setText((String)persistentHashtable.get("EditData")); } if (persistentHashtable.containsKey("BoolData")) { Boolean booleanObject = (Boolean)persistentHashtable.get("BoolData"); checkboxField.setChecked(booleanObject.booleanValue()); } if (persistentHashtable.containsKey("IntData")) { Integer intObject = (Integer)persistentHashtable.get("IntData"); numericChoiceField.setSelectedValue(intObject.intValue()); } if (persistentHashtable.containsKey("Date")){ Long longObject = (Long)persistentHashtable.get("Date"); dateField.setDate(longObject.longValue());
The pattern is the same for all primitive datatypes. Wrap them in the appropriate associated data class and put that into the hashtable.The save method is simpler because we don’t have to do all the checking: ##start public void save() throws IOException { persistentHashtable.put("EditData", editField.getText()); persistentHashtable.put("BoolData", new Boolean(checkboxField.getChecked())); persistentHashtable.put("IntData", new Integer(numericChoiceField.getSelectedValue())); persistentHashtable.put("Date", new Long(dateField.getDate())); persistentObject.commit(); }

Notice we removed the setContents method from save. The PersistentObject maintains a reference to the Hashtable throughout the lifecycle of the screen, so all we need to do is call commit and it will write the latest versions of all referenced data to persistent storage.

Clearing the Old Persistent Data from the Simulator

There’s one last thing we need to do before running the application. Because we’re using the same Persistent Store key as before, and because we’ve already persisted a String using that key, the first time we try to read the contents of the PersistentObject and cast to a Hashtable, we’ll get an exception because the contents are a String. We need to clear the simulator’s persistent data before running the application again. From the JDE Plug-in for Eclipse, you erase the simulator’s file system by selecting the BlackBerry menu, Erase Simulator File ➤ Erase File System.

You need to erase the file system to erase the old contents of the Persistent Store.

You need to erase the file system to erase the old contents of the Persistent Store.

From the JDE, the same functionality is available from the File menu, Erase Simulator File, Erase File System. You might wonder about how we’d deal with this situation on a real device. This does happen, and we’ll touch on that in shortly, but right now, let’s look at the new application in action.The usage is the same, but now we’re storing a bunch of different pieces of data:

Storing and loading a bunch of data

Storing and loading a bunch of data

Clearing Persistent Data from a Device

On a BlackBerry device, persistent data is somewhat independent of the application.What does that mean? It has to do with what types of classes you persist. If you persist only classes that are defined in the BlackBerry API, your data by default will stay behind when your application is deleted from the device. Other applications can still access it, and if you reload your application onto the device, your data will still be there. If you want your data to be removed when your application is removed, the easiest method is to store classes that are defined in your application. In our application, this is easy to accomplish. We’ll define a new class called CustomHashtable that extends Hashtable. Remember, we have to be sure to make it implement Persistable because any class that we want to persist must directly implement Persistable; it doesn’t matter if it extends a persistable class. Create the class in a new file called, containing the following code:

##start package com.beginningblackberry.persistence; import java.util.Hashtable; import net.rim.device.api.util.Persistable; public class CustomHashtable extends Hashtable implements Persistable { }

We don’t need to add anything more to this class.Just replace all the references to Hashtable in PersistableScreen with references to CustomHashtable and everything will work as before, except that when the application is removed from the device, the data will not stay behind.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status