A13 Storing Persistent Data V2
A13 Storing Persistent Data V2
09
2|Page
Contents
This tutorial will show you how to create, save and retrieve data on the device.
We are going to implement the Persistable interface to create an application which will store some
data. (Figure 1).
Figure 1
4|Page
Introduction
If we want to save an object and be able to retrieve it even after the handheld is restarted, or the
battery is removed, that object has to implement the Persistable interface.
Just a note if you plan to build applications which might have upgrades in the future: configuration
of instance data in the class and its superclasses must not change – otherwise you will not be able to
access old saved data. Adding or changing the number of classes might also make saved data
unusable.
Please note that you can always find more information about the APIs we are using in BlackBerry API
reference document which is the part of any JDE Component Pack (Figure 2). You can find it on your
computer under Start / Programs / Research in Motion / BlackBerry JDE 4.x.
Figure 2
5|Page
You should already know how to setup and configure a new BlackBerry project. If you need a
reminder please refer to the A10 tutorial. I will also assume you know how to create menu and
display items. If not please take a look at the A11 tutorial.
package com.rim.samples.loadsave;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import net.rim.device.api.util.*;
import java.util.*;
public MusicStores() {
MainScreen mainScreen = new MainScreen();
mainScreen.setTitle(new LabelField("Favourite Music Store"));
namefield = new AutoTextEditField("Store Name: ", "");
addressfield = new AutoTextEditField("Address: ", "");
phonefield = new EditField("Phone Number: ", "",
Integer.MAX_VALUE, BasicEditField.FILTER_PHONE);
specialtyfield = new EditField("Music Type: ", "",
Integer.MAX_VALUE, BasicEditField.FILTER_DEFAULT);
mainScreen.add(namefield);
mainScreen.add(addressfield);
mainScreen.add(phonefield);
mainScreen.add(specialtyfield);
mainScreen.addMenuItem(saveItem);
mainScreen.addMenuItem(getItem);
pushScreen(mainScreen);
}
As you probably noticed, we used 4 fields for 4 peices of information we want to input, load, save
and display.
You will notice that we have a Vector, and a PeristentObject declared. I will explain their purpose
shortly.
6|Page
The rest of the code sets the title, adds 3 fields, and displays the screen.
Menu Items
The command “Save” does the following things: creates a new StoreInfo object called info, and
retrieves the data from input fields and assigns them to the data in the info object. The StoreInfo
class implements the Persistable interface and therefore can be stored. To actually save the data,
we add it to the vector _data and then call the store.setContents and store.commit
methods. We’ll talk about this further in a moment. At the end we’d like to display a dialog to
inform the user that the data was saved successfully, and then clear the data on the screen.
To retrieve the data we use the store.getContents method and cast the object into our
“_data” vector. The last object in this vector is the one we are retrieving and to display the data we
assign it to the corresponding fields.
StoreInfo class
It has one vector, which is initialized in the constructor and has 4 empty Strings. Get and set
methods, just get and set the elements in their places. We do not want elements to change places,
as it will result in corrupted data. That is why we use constant values NAME, ADDRESS, PHONE and
SPECIALITY to make sure the data is always saved and read at and from the same location.
public StoreInfo() {
static {
store = PersistentStore.getPersistentObject (0xdec6a67096f833cL);
synchronized (store) {
if (store.getContents() == null) {
store.setContents(new Vector());
store.commit();
}
}
_data = new Vector();
_data = (Vector) store.getContents();
}
As you can see all the magic happens in one line. The rest of the code just checks to see if there is
existing data, and if not, creates empty data. Next, the code retrieves this data.
The key is that we use the PersistentStore class and its getPersistentObject(long
key) method. Each persistent object should have a unique key that is used to identify it when we
want to perform save or retrieve actions. In our case it is 0xdec6a67096f833cL.
I also owe you an explanation for the 3 methods we used in the code above: getContents,
commit and setContents.
In the API reference, click on “All Classes”, find the PersistentObject class and you will see all the
methods you can use on this object (Figure 3).
11 | P a g e
Figure 3
You will also notice padlocks next to all these methods. It means only one thing – to use this method
your application has to be signed.
12 | P a g e
Code signing
Before you try running this code on a device, you should know that accessing persistent storage is a
protected operation and therefore your code must be signed.
You can run the code on the simulator without the need to sign the code.
If you do not know how to sign your code please check out the A60 tutorial.
Note that Eclipse displays a light bulb with an exclamation mark next to all the code lines requiring
signatures. If you place your mouse above the icon it will tell you that usage is discouraged (Figure
4).
Figure 4
13 | P a g e
package com.rim.samples.loadsave;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import net.rim.device.api.util.*;
import java.util.*;
public MusicStores() {
MainScreen mainScreen = new MainScreen();
mainScreen.setTitle(new LabelField("Favourite Music Store"));
namefield = new AutoTextEditField("Store Name: ", "");
addressfield = new AutoTextEditField("Address: ", "");
phonefield = new EditField("Phone Number: ", "",
Integer.MAX_VALUE, BasicEditField.FILTER_PHONE);
specialtyfield = new EditField("Music Type: ", "",
Integer.MAX_VALUE, BasicEditField.FILTER_DEFAULT);
mainScreen.add(namefield);
mainScreen.add(addressfield);
mainScreen.add(phonefield);
mainScreen.add(specialtyfield);
mainScreen.addMenuItem(saveItem);
mainScreen.addMenuItem(getItem);
pushScreen(mainScreen);
}
}
Dialog.inform("Success!");
namefield.setText(null);
addressfield.setText(null);
phonefield.setText("");
specialtyfield.setText("");
}
};
namefield.setText(info.getElement(StoreInfo.NAME));
addressfield.setText(info.getElement(StoreInfo.ADDRESS));
phonefield.setText(info.getElement(StoreInfo.PHONE));
specialtyfield.setText(info.getElement(StoreInfo.SPECIALTY));
}
}
}
};
static {
store =
PersistentStore.getPersistentObject(0xdec6a67096f833cL);
synchronized (store) {
if (store.getContents() == null) {
store.setContents(new Vector());
store.commit();
}
}
_data = new Vector();
_data = (Vector) store.getContents();
}
public StoreInfo() {
_elements = new Vector(4);
for (int i = 0; i < _elements.capacity(); ++i) {
_elements.addElement(new String(""));
}
}
Other Variations
There are a number of things you might want to try with this sample application:
Links
Developer Labs:
Documentation:
Forums: