Blackberry Java SDK Development Guide

70
BlackBerry Java SDK Data Storage Version: 6.0 Development Guide

Transcript of Blackberry Java SDK Development Guide

Page 1: Blackberry Java SDK Development Guide

BlackBerry Java SDKData StorageVersion: 6.0

Development Guide

Page 2: Blackberry Java SDK Development Guide

Published: 2010-11-30SWD-1232721-1130030151-001

Page 3: Blackberry Java SDK Development Guide

Contents1 Data storage overview................................................................................................................................................................ 4

Data storage features..................................................................................................................................................................... 4

Considerations for choosing a data storage approach...................................................................................................... 5

Storage locations............................................................................................................................................................................ 5

Access to memory................................................................................................................................................................... 6

2 Storing files in the file system................................................................................................................................................... 7

Code sample: Creating a folder..................................................................................................................................................... 7

Code sample: Creating a file......................................................................................................................................................... 8

Code sample: Writing text to a file................................................................................................................................................ 9

Code sample: Reading sections of a binary file........................................................................................................................... 9

Code sample: Displaying the path to the video folder using System.getProperty()............................................................... 11

Code sample: Retrieving a list of mounted roots........................................................................................................................ 12

3 Storing data in SQLite databases............................................................................................................................................. 13

Viewing SQLite databases............................................................................................................................................................. 13

Simulate a media card........................................................................................................................................................... 13

Security of SQLite databases......................................................................................................................................................... 14

Code sample: Creating an encrypted SQLite database..................................................................................................... 15

Performance of SQLite databases................................................................................................................................................. 16

Best practice: Optimizing SQLite database performance................................................................................................. 16

Creating and deleting SQLite databases..................................................................................................................................... 18

SQLite database files............................................................................................................................................................. 18

Character encoding................................................................................................................................................................ 18

Create an SQLite database................................................................................................................................................... 19

Code sample: Creating an SQLite database....................................................................................................................... 20

Code sample: Adding a schema to an SQLite database.................................................................................................... 21

Code sample: Deleting an SQLite database....................................................................................................................... 22

Working with SQLite databases.................................................................................................................................................... 23

Using transactions................................................................................................................................................................. 24

Using SQL parameters........................................................................................................................................................... 25

Using foreign key constraints............................................................................................................................................... 29

Code sample: Inserting table data....................................................................................................................................... 29

Code sample: Retrieving table data..................................................................................................................................... 30

Page 4: Blackberry Java SDK Development Guide

Code sample: Deleting table data........................................................................................................................................ 32

Code sample: Updating table data...................................................................................................................................... 33

Code sample: Listing database tables................................................................................................................................. 34

SQLite sample application............................................................................................................................................................. 36

Overview.................................................................................................................................................................................. 36

Files in the sample application............................................................................................................................................. 36

Featured interfaces................................................................................................................................................................ 37

Featured classes..................................................................................................................................................................... 37

Install the sample application............................................................................................................................................... 38

Run the sample application................................................................................................................................................... 38

4 Storing objects persistently....................................................................................................................................................... 39

Security of persistent objects........................................................................................................................................................ 39

Restricting access to persistent objects.............................................................................................................................. 40

Performance of the persistent store............................................................................................................................................. 40

Best practice: Using efficient data structure selection...................................................................................................... 40

Best practice: Conserving object handles........................................................................................................................... 41

Cleanup of persistent objects............................................................................................................................................... 42

Creating a persistent store............................................................................................................................................................ 42

Create a persistent data store............................................................................................................................................... 42

Store persistent data.............................................................................................................................................................. 42

Store an object in a batch transaction................................................................................................................................. 43

Working with the persistent store................................................................................................................................................. 43

Retrieve persistent data......................................................................................................................................................... 43

Remove persistent data......................................................................................................................................................... 44

Remove specific persistent data from a BlackBerry Java Application.............................................................................. 44

Retrieve a collection from persistent storage..................................................................................................................... 44

5 Storing objects nonpersistently................................................................................................................................................ 46

Common uses of the runtime store............................................................................................................................................... 46

Security of the runtime store......................................................................................................................................................... 46

Protect runtime store data using code signing keys.......................................................................................................... 47

Add an object to the runtime store............................................................................................................................................... 47

Replace an object in the runtime store........................................................................................................................................ 47

Retrieve the runtime store............................................................................................................................................................. 48

Retrieve a registered runtime object............................................................................................................................................ 48

Page 5: Blackberry Java SDK Development Guide

Retrieve an unregistered runtime object..................................................................................................................................... 48

Code sample: Storing a String in the runtime store................................................................................................................... 49

Code sample: Getting a stored String from the runtime store.................................................................................................. 49

Code sample: Creating a singleton using the RuntimeStore API............................................................................................. 50

6 Storing data in the record store................................................................................................................................................ 51

Create a record store...................................................................................................................................................................... 51

Add a record to a record store....................................................................................................................................................... 51

Code sample: Adding a record to the record store............................................................................................................ 52

Retrieve a record from a record store........................................................................................................................................... 52

Retrieve all records from a record store....................................................................................................................................... 52

Code sample: Storing and retrieving data with the record store.............................................................................................. 53

7 Managing data............................................................................................................................................................................. 58

Best practice: Minimizing memory use........................................................................................................................................ 58

Removing sensitive data................................................................................................................................................................ 58

Using the Garbage Collector......................................................................................................................................................... 59

Full garbage collection on a BlackBerry device.................................................................................................................. 59

Managing low memory................................................................................................................................................................... 60

Identifying low memory availability on a BlackBerry device............................................................................................. 60

Backing up data.............................................................................................................................................................................. 60

8 Find more information................................................................................................................................................................ 62

9 Provide feedback......................................................................................................................................................................... 63

10 Glossary......................................................................................................................................................................................... 64

11 Document revision history......................................................................................................................................................... 65

12 Legal notice.................................................................................................................................................................................. 66

Page 6: Blackberry Java SDK Development Guide

Data storage overview 1

RIM provides a variety of approaches for you to store, share, and manage your application data:

Data storage approach Description and API

File system Store data in files and folders using the FileConnection API.

SQLite® database Store data in relational databases using the Database API.

Persistent store Save objects across device restarts using the PersistentStore API.

Runtime store Save objects nonpersistently, which is useful for sharing data between applications and

creating system-wide singletons, using the RuntimeStore API.

Record store Store data in the MIDP Record Management System using the RMS API.

Data storage featuresThe following table compares the data storage approaches.

Features File system SQLite

database

Persistent store Runtime store Record store

Data format Any Relational

database file

Java® object Java object Serialized

Storage locations Application

storage, external

media card, built-

in media storage

External

media card,

built-in media

storage

Application

storage

Application

storage

Application

storage

Maximum storage limit Size of partitions

the user has

access to

Size of

partitions the

user has

access to

Available

application

storage

Available

application

storage

Differs according

to BlackBerry®

Device Software

version

BlackBerry Device

Software support

4.2 or later

(FileConnection

API)

5.0 or later All 3.6 or later All

Persists across device

restarts

Yes Yes Yes No Yes

Development Guide Data storage overview

4

Page 7: Blackberry Java SDK Development Guide

Features File system SQLite

database

Persistent store Runtime store Record store

Applications can share

data

Yes Yes Yes Yes Yes

Considerations for choosing a data storage approach• The file system is typically the most efficient storage location for large, read-only files such as videos or large graphics.• For storing data other than large, read-only files, SQLite® databases are a scalable data storage option.• Memory on wireless devices can be very limited, so you should consider not storing all data on the device. BlackBerry®

devices are frequently connected so your application can access data when needed. In many cases, the best approach is tostore data across device restarts only for data that is frequently accessed.

• When you consider where to store essential data, keep in mind that microSD cards can be removed.• There is more latency in writing to application storage than there is in reading from it. For example, reading from the

persistent store is relatively fast while commits are relatively slow.• The file system and record store are standards-based approaches, while the persistent store and runtime store are specific

to BlackBerry devices. If you want your application to run on other Java® ME compatible devices, you should consider astandards-based approach.

Storage locationsDifferent BlackBerry® devices support different places to store data. The following storage locations are available, dependingon the BlackBerry device model:

Application storage This storage location is internal to the BlackBerry device. It contains the operating system, the

BlackBerry® Java® Virtual Machine, and an internal file system. Application storage is also called

flash memory and on-board memory. Application storage is the only place on a BlackBerry device

from which applications can be run. All BlackBerry devices have application storage.

External media card

storage

This storage location is a microSD card that BlackBerry device users can insert to extend the amount

of storage on their devices. It is optional and removable. A FAT file system is mounted on the media

card. MicroSD cards are supported on all devices running BlackBerry® Device Software 4.2 or later,

with the exception of the BlackBerry® 8700 Series.

Built-in media storage This storage location is an embedded multimedia card called eMMC. It is not removable. A FAT

file system is mounted on the built-in media card. Built-in media storage is also called internal

media memory and on-board device memory. Built-in media storage is included on some

BlackBerry device models.

Development Guide Storage locations

5

Page 8: Blackberry Java SDK Development Guide

Access to memory

The BlackBerry® Java® environment is designed to prevent applications from causing problems accidentally or maliciously inother applications or on the BlackBerry device. Applications can write only to the BlackBerry device memory that the BlackBerry®Java® Virtual Machine uses; they cannot access the virtual memory or the persistent storage of other applications (unless theyare specifically granted access to do so). Custom applications can only access persistent storage or user data, or communicatewith other applications, through specific APIs. Research In Motion must digitally sign applications that use certain BlackBerryAPIs to provide an audit trail of applications that use sensitive APIs.

Development Guide Storage locations

6

Page 9: Blackberry Java SDK Development Guide

Storing files in the file system 2

You can programmatically create and manage the files and folders on BlackBerry® devices with the FileConnection API. TheFileConnection API was introduced with BlackBerry® Device Software 4.2.

The FileConnection API is defined by JSR 75 and is built on the Generic Connection Framework. The main component of theFileConnection API is the FileConnection class. Unlike other Generic Connection Framework connections,FileConnection objects can be successfully returned from the Connector.open() method without referencing anexisting file or folder. This behavior allows for the creation of new files and folders on a file system. In addition to RIMdocumentation, there are many sources of information about JSR 75 and the Generic Connection Framework.

The FileConnection API is implemented in the javax.microedition.io.file package. In addition, RIM providesextensions to the FileConnection API. The net.rim.device.api.io.file package includes the following classes:

• FileSystemJournal and FileSystemJournalListener provide a way to detect changes to the file system.• ExtendedFileConnection allows the encryption and protection of files.

You can access the file system on internal storage and external media card storage:

Internal storage Internal storage is application storage or built-in media storage. All devices have internal storage. To

access internal storage, use the path file:///store. For example,

FileConnection fc = (FileConnection)Connector.open("file:///Store")

External storage You can access external media card storage only on devices with microSD cards. To access external media

card storage, use the path file:///SDCard. For example,

FileConnection fc = (FileConnection)Connector.open("file:///SDCard")

Files created by your application are not automatically deleted when your application is uninstalled.

Devices that have built-in media storage have a file system partition called System. In BlackBerry Device Software 5.0 and later,the system partition is reserved for system use and is read-only. In BlackBerry Device Software versions earlier than 5.0, thesystem partition is read/write. You can access this partition with the path file:///system.

Code sample: Creating a folderimport net.rim.device.api.system.Application;import javax.microedition.io.*;import javax.microedition.io.file.*;import java.io.IOException;

public class CreateFolderApp extends Application

Development Guide Storing files in the file system

7

Page 10: Blackberry Java SDK Development Guide

{ public static void main(String[] args) { CreateFolderApp app = new CreateFolderApp(); app.setAcceptEvents(false); try { // the final slash in the folder path is required FileConnection fc = (FileConnection)Connector.open("file:///SDCard/testfolder/"); // If no exception is thrown, the URI is valid but the folder may not exist. if (!fc.exists()) { fc.mkdir(); // create the folder if it doesn't exist } fc.close(); } catch (IOException ioe) { System.out.println(ioe.getMessage() ); } }}

Code sample: Creating a fileimport javax.microedition.io.*;import java.io.IOException;import javax.microedition.io.file.*;import net.rim.device.api.system.Application.*;

public class CreateFileApp extends Application { public static void main(String[] args) { CreateFileApp app = new CreateFileApp(); app.setAcceptEvents(false); try { FileConnection fc = (FileConnection)Connector.open("file:///store/home/user/newfile.txt"); // If no exception is thrown, then the URI is valid, but the file may or may not exist. if (!fc.exists()) { fc.create(); // create the file if it doesn't exist } fc.close(); } catch (IOException ioe)

Development Guide Code sample: Creating a file

8

Page 11: Blackberry Java SDK Development Guide

{ System.out.println(ioe.getMessage() ); } }}

Code sample: Writing text to a fileimport net.rim.device.api.system.Application;import javax.microedition.io.*;import javax.microedition.io.file.*;import java.io.IOException;import java.io.OutputStream;

public class AddFileContent extends Application { public static void main(String[] args) { AddFileContent app = new AddFileContent(); app.setAcceptEvents(false); try { FileConnection fc = (FileConnection)Connector.open("file:///store/home/user/newfile.txt"); // If no exception is thrown, then the URI is valid, but the file may or may not exist. if (!fc.exists()) { fc.create(); // create the file if it doesn't exist } OutputStream outStream = fc.openOutputStream(); outStream.write("test content".getBytes()); outStream.close(); fc.close(); } catch (IOException ioe) { System.out.println(ioe.getMessage() ); } }}

Code sample: Reading sections of a binary fileThis code sample demonstrates how to read sections of a binary file by reading header information from a .gif file. The applicationreads the width and height of the image from the header. To run the code sample you must place a .gif file in the root folder ofa media card in a BlackBerry® device.

Development Guide Code sample: Writing text to a file

9

Page 12: Blackberry Java SDK Development Guide

import net.rim.device.api.ui.*;import net.rim.device.api.io.*;import javax.microedition.io.file.*;import javax.microedition.io.*;import java.io.*;import net.rim.device.api.ui.component.*;import net.rim.device.api.ui.container.*;

public class RandomFileAccess extends UiApplication{ public static void main(String[] args) { RandomFileAccess app = new RandomFileAccess(); app.enterEventDispatcher(); } public RandomFileAccess() { pushScreen(new HomeScreen()); }}

class HomeScreen extends MainScreen{

public HomeScreen() { setTitle("Random File Access Sample"); try { FileConnection fc = (FileConnection)Connector.open("file:///SDCard/test.gif"); boolean bFileExists = fc.exists(); if (!bFileExists) { Dialog.alert("Cannot find specified GIF file."); System.exit(0); } DataInputStream in = fc.openDataInputStream(); byte[] widthBytes = new byte[2]; byte[] heightBytes = new byte[2]; if ( in instanceof Seekable ) { ((Seekable) in).setPosition(6); in.read(widthBytes,0,2); ((Seekable) in).setPosition(8); in.read(heightBytes,0,2); }

Development Guide Code sample: Reading sections of a binary file

10

Page 13: Blackberry Java SDK Development Guide

int widthPixels = widthBytes[0] + 256 * widthBytes[1]; int heightPixels = heightBytes[0] + 256 * heightBytes[1]; add(new LabelField("Width: " + widthPixels + "\nHeight: " + heightPixels)); in.close(); fc.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } }

Code sample: Displaying the path to the video folder usingSystem.getProperty()import net.rim.device.api.ui.component.LabelField.*;import net.rim.device.api.ui.container.MainScreen.*;import net.rim.device.api.ui.UiApplication.*;

public class GetVidDir extends UiApplication{ public static void main(String args[]) { GetVidDir app = new GetVidDir(); app.enterEventDispatcher(); } public GetVidDir() { HomeScreen hs = new HomeScreen(); pushScreen(hs); }}

class HomeScreen extends MainScreen{ public HomeScreen() { LabelField msg = new LabelField(System.getProperty("fileconn.dir.videos")); add(msg); }}

Development Guide Code sample: Displaying the path to the video folder using System.getProperty()

11

Page 14: Blackberry Java SDK Development Guide

Code sample: Retrieving a list of mounted rootsimport java.util.Enumeration.*;import javax.microedition.io.file.FileSystemRegistry,*;import net.rim.device.api.ui.component.LabelField.*;import net.rim.device.api.ui.container.MainScreen.*;import net.rim.device.api.ui.UiApplication.*;

public class ListMountedRoots extends UiApplication { public static void main(String[] args) { ListMountedRoots app = new ListMountedRoots(); app.enterEventDispatcher(); } public ListMountedRoots() { pushScreen(new HomeScreen()); }}

class HomeScreen extends MainScreen{ public HomeScreen() { StringBuffer msg = new StringBuffer( “The mounted roots are:\n”); Enumeration e = FileSystemRegistry.listRoots(); while (e.hasMoreElements()) { msg.append( e.nextElement() ); msg.append( ‘\n’ ); } add(new LabelField(msg)); }

}

Development Guide Code sample: Retrieving a list of mounted roots

12

Page 15: Blackberry Java SDK Development Guide

Storing data in SQLite databases 3

SQLite® databases require no configuration or administration. Other than schema and data, the database footprint is very small(around 300 KB).

To create and use SQLite databases in a Java application, you must use the Database API. The classes required for SQLite databasesare in the net.rim.device.api.database package. The Database API was introduced with BlackBerry® Device Software5.0.

BlackBerry Device Software 6.0 uses SQLite version 3.6.21. BlackBerry Device Software 5.0 uses SQLite version 3.6.16.

Note: There are other ways to use SQLite databases on a BlackBerry device. They are BlackBerry® WebWorks™ applications,HTML5, and Google® Gears™. For more information, see docs.blackberry.com.

Viewing SQLite databasesSQLite® database viewers are available from third-party vendors. These viewers can be useful aids to your database developmentprocess. Database viewers are especially useful for viewing changes to a database. When you run an SQL statement, you can seethe result in the database viewer immediately.

An SQLite database viewer runs on your computer, not on the BlackBerry® device. To use the viewer, configure the BlackBerrySmartphone Simulator to emulate a microSD card. Then when you run your application, the database is stored in a directory onyour desktop computer and the database viewer can read it.

SQLite database viewers cannot work on encrypted databases. You can encrypt the database when your SQLite application isfinished.

Simulate a media cardTo view SQLite® databases in a database viewer, you might have to configure the BlackBerry® Smartphone Simulator to emulatea media card. By default, database files are stored on a media card.

1. Create a folder on your computer to store emulation files for the media card.

2. On the Simulate menu, click Change SD Card.

3. Click Add Directory.

4. Navigate to and click the folder you created.

5. Click OK.

6. Click Close.

Development Guide Storing data in SQLite databases

13

Page 16: Blackberry Java SDK Development Guide

Security of SQLite databasesYour SQLite® database can have the following security settings:

• Not encrypted, accessible from any application on the BlackBerry® device• Encrypted, accessible from any application on the device• Encrypted and protected, accessible only from applications on the device that are signed with the code signing key

There is no way to create a non-encrypted database and restrict its usage to only one application. That is because there are otherways (using file I/O operations) to read a non-encrypted database file from other applications.

You implement both encryption and protection with the DatabaseSecurityOptions class.

EncryptionThe algorithm used to implement SQLite encryption is AES 256.

An encrypted database cannot be moved to another device: it can be opened only on the device where it was originally created.To transfer an encrypted database to another device, you must first decrypt it.

An application can open or create an encrypted database only when the device is unlocked. If a database is open when a deviceis locked, the database continues to be readable and writable.

Encryption does not protect your database from being accessible to other applications on the device. To restrict access, you mustsign the database with a code signing key.

The following code sample creates a database that is encrypted but not signed. It creates a DatabaseSecurityOptionsobject called dbso that passes true as the single parameter value:

try{ URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyEncryptedDatabase.db"); DatabaseSecurityOptions dbso = new DatabaseSecurityOptions(true); d = DatabaseFactory.create(myURI,dbso); d.close();}catch ( Exception e ){ System.out.println( e.getMessage() ); e.printStackTrace();}

Encryption and protectionIf you want to restrict a database so that it can be accessed only by the application it is a part of, you should sign the databasewith a code signing key. To restrict access to one application, you should use a unique key that you generate using the SigningAuthority tool. This signing is separate from the code signing you do for controlled APIs.

Development Guide Security of SQLite databases

14

Page 17: Blackberry Java SDK Development Guide

You can also use the code signing key to share access to the database with other specific applications. When multiple applicationsare signed with the same key, they all have access to the database.

To specify that a database is encrypted and signed, you have a choice of two identical constructors. The following code sampleencrypts and protects an existing database. First, the code sample retrieves the code signing key from a file called XYZ. It thenencrypts and signs the database. If the database is already encrypted, the method exits gracefully.

CodeSigningKey codeSigningKey = CodeSigningKey.get(CodeModuleManager.getModuleHandle( "SQLiteDemo" ), "XYZ"); try { DatabaseFactory.encrypt(uri, new DatabaseSecurityOptions(codeSigningKey)); } catch(DatabaseException dbe) { errorDialog("Encryption failed - " + dbe.toString()); }

Code sample: Creating an encrypted SQLite database

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.database.*;import net.rim.device.api.io.*;

public class CreateEncryptedDatabase extends UiApplication{ public static void main(String[] args) { CreateEncryptedDatabase theApp = new CreateEncryptedDatabase(); theApp.enterEventDispatcher(); }

public CreateEncryptedDatabase() { pushScreen(new CreateEncryptedDatabaseScreen()); }}

class CreateEncryptedDatabaseScreen extends MainScreen{ Database d; public CreateEncryptedDatabaseScreen() { LabelField title = new LabelField("SQLite Create Encrypted Database Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

Development Guide Security of SQLite databases

15

Page 18: Blackberry Java SDK Development Guide

setTitle(title); add(new RichTextField("Creating an encrypted database called " + "MyEncryptedDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyEncryptedDatabase.db"); DatabaseSecurityOptions dbso = new DatabaseSecurityOptions(true); d = DatabaseFactory.create(myURI,dbso); d.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Performance of SQLite databasesCompared to a computer, a smartphone provides a very constrained environment for an SQLite® database. To achieve optimalperformance on a BlackBerry® device, you should build your database with these constraints in mind.

On a BlackBerry device, only one read-write database connection to an SQLite database can be made at a time. Other databaseconnections are read-only. There is a limit of 16 concurrent database connections, and three to six of those are used by the mediaapplication.

There are constraints on the amount of RAM available to an SQLite database for storing internal data structures for schemasand transactions, and to support binding BLOBs into a table. In BlackBerry® Device Software 5.0, the limit is 512 KB. In BlackBerryDevice Software 6.0, the limit is 5 MB. The entire database schema is loaded into memory when an SQLite database is openedand persists until the database is closed. The schema for each table, trigger, index, and so on takes up a certain amount of RAM.In addition, the memory limit for the binding of BLOBs is significantly less than the overall memory limit and will vary dependingon what is left over after allocating memory for SQLite data structures, schemas, and transactions in progress.

If you plan to create a database with a large schema or insert large BLOBs, you should test the database on your target BlackBerrydevices to make sure that the devices have adequate memory.

The maximum SQL query length is 4 KB.

Best practice: Optimizing SQLite database performance

Consider the following guidelines:

Development Guide Performance of SQLite databases

16

Page 19: Blackberry Java SDK Development Guide

Best practice Description

Store as little data as

possible

Most of the processing time of SQLite® databases is taken up by reading and writing to storage.

Less data generally means fewer reads and writes. The SQLite database engine caches frequently

accessed database pages. By storing less data, you can increase the probability that the SQLite

database engine retrieves requested data more quickly from the cache instead of from the relatively

slow storage access.

Use explicit

transactions

If you do not use explicit transactions, a transaction begins before each statement is executed and

ends after the statement is executed. This default behavior is inefficient. It requires the opening,

reopening, writing to, and closing of the journal file for each statement. With explicit transactions,

you can group statements.

Create efficient

indexes

Indexes can greatly reduce the time required to scan a table. Consider the following guidelines:

• The order of columns in an index affects performance. Columns that are typically used in WHERE

clauses should be placed first, followed by columns that are typically used in ORDER BY clauses.

• For columns containing data that is retrieved, create a covering index.

• Avoid duplicate indexes. The SQLite database engine automatically creates indexes for columns

that have UNIQUE or PRIMARY KEY constraints.

Minimize the size of

rows

If you have a very wide column, consider putting it in a separate table.

Store BLOBs

appropriately

If your data includes BLOBs, consider storing each BLOB in a separate table. If the BLOBs are very

large, you can store them as files outside the database (and store the path to each file in the database),

but this practice introduces overhead for filename lookups.

Consider using

temporary tables

If you do not need the data to be available following a restart of the BlackBerry devices, use the

CREATE TEMP TABLE statement instead of CREATE TABLE.

Use SQL parameters To execute a set of statements of the same format, first prepare a generic statement that uses SQL

parameters. You can execute the statement by iterating through the variable values and binding the

values to the named variables in each iteration.

Avoid subqueries In some cases, the SQLite database engine stores subquery results in a temporary file, which can

slow down processing.

Defragment the

database

Use the SQLite VACUUM command to defragment the database. This process also reduces the size

of the database file.

Development Guide Performance of SQLite databases

17

Page 20: Blackberry Java SDK Development Guide

Best practice Description

Consider the order of

columns in table

declarations

The order of columns in a table declaration affects performance, especially in the absence of an

index, because the SQLite database engine scans the columns in the order defined in the table

declaration. Columns that contain small amounts of data that is frequently accessed should be placed

before columns that contain large amounts of data that is infrequently accessed.

Creating and deleting SQLite databasesYou can create temporary or permanent databases. The CREATE TABLE statement creates a permanent, or regular, database.When you do not need to store data across device resets, you should use the CREATE TEMP TABLE statement to create temporarytables, as they are more efficient. The temporary tables that are created are stored in a temporary database along with allassociated indexes, triggers, and views. The temporary database file is deleted automatically when the database connection isclosed.

When your application is removed, permanent databases associated with your application are not automatically deleted.

SQLite database files

Each SQLite® database is stored in a single file. If you specify only the database name as the parameter value toDatabaseFactory.create(), the database file is created in external media card storage. The default location for thedatabase file is /SDCard/databases/application_name/. The name of the application that creates the database is included inthe default path to avoid name collisions.

You cannot store SQLite databases in application storage.

External media card storage is the preferred storage location for databases if the BlackBerry® device supports it. On devices thatsupport external media card storage, you can create databases in external media card storage by specifying the path /SDcard/.

If your application is designed to store your SQLite database in built-in media storage, you should implement your applicationso that it is easy to modify the code to change the storage location of the database. On devices that support built-in mediastorage, you can create databases in built-in media storage by specifying the path /store/ .

When your application is uninstalled, the SQLite databases associated with it are not automatically removed.

Character encoding

The Database API uses UTF-8 character encoding. Java® stores strings internally in UTF-8, so you don't need to do any encodingor conversion.

The SQLite statement PRAGMA is not supported in the Database API, so you can't use PRAGMA ENCODING to set anotherencoding. You must use UTF-8 supported characters in your SQLite database.

Development Guide Creating and deleting SQLite databases

18

Page 21: Blackberry Java SDK Development Guide

Create an SQLite database1. Import the required libraries.

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.database.*;import net.rim.device.api.io.*;

2. Create the framework for the application by extending the UiApplication class. This class represents your application.Provide a main() method for the new class. In the main() method, create an instance of the new class and invoke theenterEventDispatcher() method to enable the application to receive events. Provide a constructor for the new class.In the constructor, invoke the pushScreen method to display the custom screen for the application.

public class CreateDatabase extends UiApplication{ public static void main(String[] args) { CreateDatabase theApp = new CreateDatabase(); theApp.enterEventDispatcher(); } public CreateDatabase() { pushScreen(new CreateDatabaseScreen()); } }

3. Create the screen for the application by extending the MainScreen class. Provide a constructor for the new class. In theconstructor, create the title for the screen with a LabelField object and display it by invoking the setTitle() method.Invoke the add() method to display a text field on the screen.

class CreateDatabaseScreen extends MainScreen{ public CreateDatabaseScreen() { LabelField title = new LabelField("SQLite Create Database Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Creating a database called " + "MyTestDatabase.db on the SDCard.")); }}

Development Guide Creating and deleting SQLite databases

19

Page 22: Blackberry Java SDK Development Guide

4. Create a URI that represents the database file by invoking the static create() method of the URI class. Invoke thecreate() method of the DatabaseFactory class to create the database that corresponds to the URI that you created.This creates an SQLite® database on the microSD card of the BlackBerry® device. If you do not specify a full path, thedatabase is created in a folder named after your application.

try{ URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); Database db = DatabaseFactory.create(myURI);}catch ( Exception e ){ System.out.println( e.getMessage() ); e.printStackTrace();}

5. When you are finished using the database, it is good practice to close it.

db.close();

After you finish:

After creating a database, verify that the database file was created. You can do this in any of the following ways:

• View the database in a database viewer• Look in the file system for the database file, and verify that it is not zero size• Invoke DatabaseFactory.exists()

Code sample: Creating an SQLite database

import net.rim.device.api.ui.component.*;import net.rim.device.api.ui.container.*;import net.rim.device.api.database.*;import net.rim.device.api.io.*;import net.rim.device.api.ui.*;

public class CreateDatabase extends UiApplication{ public static void main(String[] args) { CreateDatabase theApp = new CreateDatabase(); theApp.enterEventDispatcher(); } public CreateDatabase() { pushScreen(new CreateDatabaseScreen());

Development Guide Creating and deleting SQLite databases

20

Page 23: Blackberry Java SDK Development Guide

} }

class CreateDatabaseScreen extends MainScreen{ Database d; public CreateDatabaseScreen() { LabelField title = new LabelField("SQLite Create Database Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Creating a database called " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.create(myURI); d.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Adding a schema to an SQLite database

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.database.*;import net.rim.device.api.io.*;

public class CreateDatabaseSchema extends UiApplication{ public static void main(String[] args) { CreateDatabaseSchema theApp = new CreateDatabaseSchema(); theApp.enterEventDispatcher(); } public CreateDatabaseSchema() { pushScreen(new CreateDatabaseSchemaScreen()); } }

Development Guide Creating and deleting SQLite databases

21

Page 24: Blackberry Java SDK Development Guide

class CreateDatabaseSchemaScreen extends MainScreen{ Database d; public CreateDatabaseSchemaScreen() { LabelField title = new LabelField("SQLite Create " + "Database Schema Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Adding a table to a database called " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("/SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createStatement( "CREATE TABLE 'People' ( " + "'Name' TEXT, " + "'Age' INTEGER )" ); st.prepare(); st.execute(); st.close(); d.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Deleting an SQLite database

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.database.*;import net.rim.device.api.io.*;

public class DeleteDatabase extends UiApplication{ public static void main(String[] args) { DeleteDatabase theApp = new DeleteDatabase(); theApp.enterEventDispatcher();

Development Guide Creating and deleting SQLite databases

22

Page 25: Blackberry Java SDK Development Guide

} public DeleteDatabase() { pushScreen(new DeleteDatabaseScreen()); } }

class DeleteDatabaseScreen extends MainScreen{ Database d; public DeleteDatabaseScreen() { LabelField title = new LabelField("SQLite Delete Database Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Deleting a database called " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); DatabaseFactory.delete(myURI); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Working with SQLite databasesOnce you have created an SQLite® database, you can use SQL statements to add data, retrieve data, and modify the database.

The list of supported SQL statements and their syntax is available on the SQLite web site. The Database API does not supportthe following SQLite statements: ATTACH, DETACH, FTS2, PRAGMA, and RTREE.

The following steps outline the basic procedure for running statements:

1. Create an SQL statement by invoking Database.createStatement().

2. Prepare the statement to run by invoking Statement.prepare().

3. Run the statement. If the statement might return results, run it by invoking Statement.getCursor(). Otherwise, useStatement.execute().

Development Guide Working with SQLite databases

23

Page 26: Blackberry Java SDK Development Guide

4. If the statement returns a result set, retrieve the result set by iterating over the returned cursor row by row. Do this usingthe Cursor class, which works in all circumstances but is forward-only. For birectional cursor movement, but only for smallresult sets, use BufferedCursor.

Using transactions

SQLite® statements always run in transactions. If the statement runs successfully, the transaction is automatically committed.If the statement fails, the transaction is rolled back.

By default, a separate transaction is created for each SQLite statement, which is less efficient than running multiple statementsin one transaction. You can usually improve performance by explicitly specifying transactions for groups of statements. You canrun multiple statements in one transaction using Database.beginTransaction() andDatabase.commitTransaction() around groups of statements.

Nested transactions are not supported.

Code sample: Using transactions

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.database.*;import net.rim.device.api.io.*;public class UsingTransactions extends UiApplication{ public static void main(String[] args) { UsingTransactions theApp = new UsingTransactions(); theApp.enterEventDispatcher(); } public UsingTransactions() { }}

class UsingTransactionsScreen extends MainScreen{ Database d; public UsingTransactionsScreen() { LabelField title = new LabelField("SQLite Using Transactions Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Updating data in one transaction in MyTestDatabase.db."));

Development Guide Working with SQLite databases

24

Page 27: Blackberry Java SDK Development Guide

try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); d.beginTransaction(); Statement st = d.createStatement("UPDATE People SET Age=7 " + "WHERE Name='Sophie'"); st.prepare(); st.execute(); st.reset(); st = d.createStatement("UPDATE People SET Age=4 " + "WHERE Name='Karen'"); st.prepare(); st.execute(); d.commitTransaction(); st.close(); d.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Using SQL parameters

When you create an SQL statement, you can create SQL parameters in order to reuse the statement with different values. Thispractice can provide performance benefits. Prepare generic statements that use named variables, and then execute thestatements when they are required by iterating through the variable values, binding the values to the named variables in eachiteration.

You can choose from the following ways to number the parameters:

• A question mark (?) in the statement causes each parameter to be numbered sequentially, starting from 1.• A question mark followed by an integer (?NNN) in the statement provides each parameter with the number NNN.

You can use the bind() method to provide names for SQL parameters. The bind() method takes the number of the parameterand the value to be bound to it. If you use a number outside of the allowed range, a DatabaseException is thrown. Allbindings can be reset using Statement.reset().

Here's an example of a statement that uses parameters to create an upper bound and lower bound that can be defined eachtime the statement is run. This example numbers the parameters sequentially.

Development Guide Working with SQLite databases

25

Page 28: Blackberry Java SDK Development Guide

Statement s = Database.createStatement("SELECT * FROM T WHERE a < ? AND a > ?"); s.prepare(); s.bind(1, upperBound); s.bind(2, lowerBound); Cursor c = s.getCursor();

Here's an example of the same statement, except that explicit numbers are specified for the parameters:

Statement s = Database.createStatement("SELECT * FROM T WHERE a < ?5 AND a > ?12"); s.prepare(); s.bind(5, upperBound); s.bind(12, lowerBound);

The getFormalName() method converts a parameter index to an SQL parameter name. For getFormalName() to be ableto return the parameter name, you must provide a name in the query. For example, when you call getFormalName(1), thestatement "SELECT * FROM T WHERE a = :a" returns :a. When parameters such as a question mark (?) are used as placeholders,getFormalName() cannot return a parameter name. For example, getFormalName(1) will not return the name for theparameter in this statement: "SELECT * FROM T WHERE a = ?"

Code sample: Creating a parameterized update

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.database.*;import net.rim.device.api.io.*;import java.util.*;

public class ParameterizedUpdate extends UiApplication{ public static void main(String[] args) { ParameterizedUpdate theApp = new ParameterizedUpdate(); theApp.enterEventDispatcher(); } public ParameterizedUpdate() { pushScreen(new ParameterizedUpdateScreen()); } } class ParameterizedUpdateScreen extends MainScreen { Database d; public ParameterizedUpdateScreen() { LabelField title = new LabelField("SQLite Parameterized Update Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH);

Development Guide Working with SQLite databases

26

Page 29: Blackberry Java SDK Development Guide

setTitle(title); add(new RichTextField("Attempting to update data in " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createStatement("UPDATE People SET Age=? WHERE Name=?"); st.prepare(); Hashtable ht = new Hashtable(2); ht.put("Sophie", new Integer(10)); ht.put("Karen", new Integer(7)); Enumeration names = ht.keys(); Enumeration ages = ht.elements(); while (names.hasMoreElements()) { Integer iAge = (Integer)ages.nextElement(); String strName = (String)names.nextElement(); st.bind(1,iAge.intValue()); st.bind(2,strName); st.execute(); st.reset(); } st.close(); d.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Creating a parameterized insert

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.database.*;import net.rim.device.api.io.*;import java.util.*;

public class ParameterizedInsert extends UiApplication

Development Guide Working with SQLite databases

27

Page 30: Blackberry Java SDK Development Guide

{public static void main(String[] args){ ParameterizedInsert theApp = new ParameterizedInsert(); theApp.enterEventDispatcher();}public ParameterizedInsert(){ pushScreen(new ParameterizedInsertScreen());}

}class ParameterizedInsertScreen extends MainScreen{ Database d; public ParameterizedInsertScreen() { LabelField title = new LabelField("SQLite Insert Data " + "Schema Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Attempting to insert data into " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI);

Statement st = d.createStatement("INSERT INTO People(Name,Age) " + "VALUES (?,?)"); st.prepare();

Hashtable ht = new Hashtable(4); ht.put("Sophie", new Integer(6)); ht.put("Karen", new Integer(3)); ht.put("Kevin", new Integer(82)); ht.put("Cindy", new Integer(12));

Enumeration names = ht.keys(); Enumeration ages = ht.elements();

while (names.hasMoreElements()) { String strName = (String)names.nextElement(); Integer iAge = (Integer)ages.nextElement(); st.bind(1,strName); st.bind(2,iAge.intValue()); st.execute(); st.reset(); }

Development Guide Working with SQLite databases

28

Page 31: Blackberry Java SDK Development Guide

st.close(); d.close();

} catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); }}}

Using foreign key constraints

If you create foreign keys for your database, you can enforce the use of them by setting a database option calledforeign_key_constraints.

You can set this option when you create the database. To be effective, you must set it again each time you open the database.

This feature was added in BlackBerry® Device Software 6.0.

Code sample: Enforcing the use of foreign keys

The following code sample shows how to enforce foreign constraints before opening or creating a database. The code samplecreates the DatabaseOptions object with foreign key constraints set to on.

DatabaseOptions dbo = new DatabaseOptions();dbo.set("foreign_key_constraints","on");Database d = DatabaseFactory.openOrCreate("test.db", dbo);

Code sample: Inserting table data

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.database.*;import net.rim.device.api.io.*;

public class InsertData extends UiApplication{ public static void main(String[] args) { InsertData theApp = new InsertData(); theApp.enterEventDispatcher(); } public InsertData()

Development Guide Working with SQLite databases

29

Page 32: Blackberry Java SDK Development Guide

{ pushScreen(new InsertDataScreen()); } }

class InsertDataScreen extends MainScreen{ Database d; public InsertDataScreen() { LabelField title = new LabelField("SQLite Insert Data " + "Schema Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Attempting to insert data into " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createStatement("INSERT INTO People(Name,Age) " + "VALUES ('John',37)"); st.prepare(); st.execute(); st.close(); d.close();

} catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Retrieving table data

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.database.*;import net.rim.device.api.io.*;

public class ReadData extends UiApplication{

Development Guide Working with SQLite databases

30

Page 33: Blackberry Java SDK Development Guide

public static void main(String[] args) { ReadData theApp = new ReadData(); theApp.enterEventDispatcher(); } public ReadData() { pushScreen(new ReadDataScreen()); } }

class ReadDataScreen extends MainScreen{ Database d; public ReadDataScreen() { LabelField title = new LabelField("SQLite Read Table Data Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Attempting to retrieve data from " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createStatement("SELECT Name,Age FROM People");

st.prepare(); net.rim.device.api.database.Cursor c = st.getCursor(); Row r; int i = 0; while(c.next()) { r = c.getRow(); i++; add(new RichTextField(i + ". Name = " + r.getString(0) + " , " + "Age = " + r.getInteger(1))); } if (i==0) { add(new RichTextField("No data in the People table.")); } st.close(); d.close();

}

Development Guide Working with SQLite databases

31

Page 34: Blackberry Java SDK Development Guide

catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Deleting table dataTo delete data in a table, use the DELETE statement. To delete a table and its schema, use the DROP TABLE statement. Thefollowing example shows the DELETE statement.

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.database.*;import net.rim.device.api.io.*;

public class DeleteData extends UiApplication{ public static void main(String[] args) { DeleteData theApp = new DeleteData(); theApp.enterEventDispatcher(); } public DeleteData() { pushScreen(new DeleteDataScreen()); } }

class DeleteDataScreen extends MainScreen{ Database d; public DeleteDataScreen() { LabelField title = new LabelField("SQLite Delete Database Data", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Attempting to delete data from " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI);

Development Guide Working with SQLite databases

32

Page 35: Blackberry Java SDK Development Guide

Statement st = d.createStatement("DELETE FROM People"); st.prepare(); st.execute(); st.close(); d.close();

} catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Updating table data

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.database.*;import net.rim.device.api.io.*;

public class UpdateData extends UiApplication{ public static void main(String[] args) { UpdateData theApp = new UpdateData(); theApp.enterEventDispatcher(); } public UpdateData() { pushScreen(new UpdateDataScreen()); } }

class UpdateDataScreen extends MainScreen{ Database d; public UpdateDataScreen() { LabelField title = new LabelField("SQLite Update Data Sample", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Trying to update data in MyTestDatabase.db.")); try {

Development Guide Working with SQLite databases

33

Page 36: Blackberry Java SDK Development Guide

URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createStatement("UPDATE People SET Age=38 " + "WHERE Name='John'"); st.prepare(); st.execute(); st.close(); d.close();

} catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Code sample: Listing database tables

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.database.*;import net.rim.device.api.io.*;

public class ListTables extends UiApplication{ public static void main(String[] args) { ListTables theApp = new ListTables(); theApp.enterEventDispatcher(); } public ListTables() { pushScreen(new ListTablesScreen()); } }

class ListTablesScreen extends MainScreen{ Database d; public ListTablesScreen() { LabelField title = new LabelField("SQLite List Database Tables", LabelField.ELLIPSIS |

Development Guide Working with SQLite databases

34

Page 37: Blackberry Java SDK Development Guide

LabelField.USE_ALL_WIDTH); setTitle(title); add(new RichTextField("Attempting to list tables in " + "MyTestDatabase.db on the SDCard.")); try { URI myURI = URI.create("file:///SDCard/Databases/SQLite_Guide/" + "MyTestDatabase.db"); d = DatabaseFactory.open(myURI); Statement st = d.createStatement("SELECT name FROM " + " sqlite_master " + "WHERE type='table'" + "ORDER BY name"); st.prepare(); net.rim.device.api.database.Cursor c = st.getCursor(); Row r; int i = 0; while(c.next()) { r = c.getRow(); i++; add(new RichTextField(i + ". Table: " + r.getString(0))); } if (i==0) { add(new RichTextField("There are no tables " + " in the MyTestDatabase database.")); } st.close(); d.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); e.printStackTrace(); } }}

Development Guide

35

Page 38: Blackberry Java SDK Development Guide

SQLite sample application

Overview

The SQLite® database sample application demonstrates how to create a persistent relational database that is stored on theBlackBerry® device and how to change the entries in the database.

The database contains two tables that are called Category and DirectoryItems. The DirectoryItems table containsitems that simulate entries in a business directory list. Each DirectoryItem entry also contains a CategoryID field thatmust match a category_id entry in the Category table (for instance, Category.category_id is a foreign key forDirectoryItem.categoryID).

The sample application displays the entries in the tables as a collapsible tree structure with Category entries as parent nodesand DirectoryItem entries as child nodes of the Category nodes that they are associated with. The sample applicationprovides menu items for adding a new category or directory item and for changing or deleting the directory item.

This sample application uses APIs that are designed to be secure.The application must be signed before it can be run. For moreinformation about code signing, see the BlackBerry Signing Authority Tool Administration Guide.

Files in the sample application

File name Description

SQLiteDemo.java • This file contains the application entry point.

• This file contains the application's constructor, which creates an encrypted

database on the media card of the BlackBerry® device if it is inserted or in

device memory. If a media card is not inserted and the BlackBerry device

supports storing the database in device memory, the encrypted database is

created in device memory.

• This file creates and displays an instance of SQLiteDemoScreen.

SQLiteDemoScreen.java • This file contains the application's main screen, which displays the database

in a collapsible tree structure with Category entries as parent nodes and

associated DirectoryItems as their children.

• This file contains helper methods to populate the tree when the screen is

initialized.

Development Guide SQLite sample application

36

Page 39: Blackberry Java SDK Development Guide

File name Description

• This file contains menu items for adding, updating, and deleting categories

and directory items.

SQLManager.java This file contains all the methods for adding, updating, and deleting categories and

directory items (for instance, all of the database manipulation methods).

ItemScreen.java This file contains the screen, which contains fields for adding and changing

categories and directory items.

Category.java • This file defines the Category entries in the database.

• This file provides accessor methods for the Category fields.

DirectoryItems.java • This file defines the DirectoryItems entries in the database.

• This file provides accessor methods for the DirectoryItems fields.

SQLiteDemoDirectory • This file contains the database.

• This file comes prepopulated with sample entries.

Featured interfaces

net.rim.device.api.DatabaseThe Database interface represents the database. This interface provides methods for changing a database on the BlackBerrydevice, including methods for creating SQL statements to add, delete, or update records in the database and methods forcommitting and canceling transactions in the database. This interface also provides methods for setting and retrieving thedatabase's metadata.

To create the database, you can use one of the methods of the DatabaseFactory class.

The sample application uses this interface to create statements to insert, delete, and update records in the database.

net.rim.device.api.StatementThe Statement interface represents an SQL statement. You can use the Statement interface to retrieve, add, delete, orchange entries in the database.

net.rim.device.api.CursorThe Cursor interface provides methods for traversing a result set that is retrieved using the Statement object. AStatement object creates the Cursor object using the Statement.getCursor() method as part of its query process.Therefore, a Cursor is always associated with a specific query.

Featured classes

net.rim.device.api.database.Row

Development Guide SQLite sample application

37

Page 40: Blackberry Java SDK Development Guide

The Row class represents a row in a result set that a SELECT query returns.

This class provides methods for retrieving column indices in the Row object and the values stored in the Row object's columns.

You create this class using the Cursor.getRow() method.

net.rim.device.api.database.DatabaseFactoryThe DatabaseFactory class provides methods for creating, opening, configuring, and deleting a new or existingDatabase. Configuration options include persistent or nonpersistent storage and encryption.

To create a new database, you must use the DatabaseFactory.openOrCreate() method or theDatabaseFactory.create() method. If you have already created the database, theDatabaseFactory.openOrCreate() method returns a reference to the database.

Create the database on a media card instead of in device memory. Only certain BlackBerry® devices support storing an SQLitedatabase in device memory.

Install the sample application1. In Eclipse®, on the File menu, click Import.

2. In the Import dialog box, expand the BlackBerry folder.

3. Click Import BlackBerry Samples.

4. Click Next.

5. Perform one of the following actions:• To specify a specific JRE™, select the Use a project specific JRE option.

• To specify the default JRE in the workspace, select the Use default JRE option.

6. In the BlackBerry Projects section, click Deselect All.

7. Select the check box beside the SQLiteDemo project.

8. Click Finish.

Run the sample application1. In Eclipse®, in the Navigator pane, right-click the SQLiteDemo folder.

2. Click Run As > BlackBerry Simulator.

3. If the BlackBerry® Smartphone Simulator did not display the message "Media card inserted" on startup, you must Simulatea media card.

4. If necessary, on the Home screen of the BlackBerry® Smartphone Simulator, click the Downloads folder.

5. Click the SQLite Demo icon.

Development Guide SQLite sample application

38

Page 41: Blackberry Java SDK Development Guide

Storing objects persistently 4

The persistent store lets you save objects to persistent memory. The objects are retained in memory after a BlackBerry® devicerestarts. The persistent store is included in all versions of BlackBerry® Device Software.

With the Persistent Store API, you can save entire Java® objects to memory without having to serialize the data first. When yourapplication starts, it can retrieve the Java object from memory and process the data. The Persistent Store API does not providea relational database model. You must create an effective object model and manage the relationships between objects, asnecessary, using indices and hash tables.

The Persistent Store API is implemented in the PersistentObject class, PersistentStore class, and EventLoggerclass, all of which are provided in the net.rim.device.api.system package, and the Persistable interface, whichis provided in the net.rim.device.api.util package.

Data is stored as instances of PersistentObject. PersistentObject can be any object that implements thePersistable interface. The Persistent Store API allows the implicit persistence of classes, so the following data typesautomatically implement the Persistable interface and can also be stored in the persistent store:

• java.lang.Boolean• java.lang.Byte• java.lang.Character• java.lang.Integer• java.lang.Long• java.lang.Object• java.lang.Short• java.lang.String• java.util.Vector• java.util.Hashtable

The storage for each application is distinct because each object in the persistent store is associated with a 64-bit ID (type long).

Security of persistent objectsBlackBerry® Device Software provides two main ways to secure objects in the persistent store:

• Restrict access to the objects with the ControlledAccess class and code signing keys.• Encrypt and decrypt objects with the PersistentContent class.

Depending on the needs of your application, you could use both, one, or neither of these approaches.

Development Guide Storing objects persistently

39

Page 42: Blackberry Java SDK Development Guide

Restricting access to persistent objects

If you want to permit only specific, authorized applications to access your application data, you should use theControlledAccess class in conjunction with key generation and a key-signing procedure. To restrict access to your data,you can:

• Create a signing key using the BlackBerry® Signing Authority Tool.• Wrap the PersistentObject in a ControlledAccess object that is associated with the signing key.• Use the same signing key for each application that you want to allow to access the protected data.

For detailed instructions, see Protect persistent objects from access by unauthorized applications.

Protect persistent data using code signing keys

1. Import the required classes and interfaces.

import java.util.Hashtable;import net.rim.device.api.system.PersistentObject;

2. Create a hash ID for the object you want to store in a persistent object.

long MY_DATA_ID = 0x33abf322367f9018L;Hashtable myHashtable = new Hashtable();

3. Store the object in the persistent object and protect the object with the CodeSigningKey object. For example, after aBlackBerry device application runs the following line of code, only .cod files that are signed with the RSAE .key file can reador overwrite the object in the persistent object.

persistentObject.setContents( new ControlledAccess( myHashtable, key ) );

4. Make sure that the object is protected, and invoke getContents using the CodeSigningKey object as a parameter.

Hashtable myHashtable = (Hashtable) persistentObject.getContents( key );

Performance of the persistent storeThe persistent store exists in application storage. There is more latency in writing to application storage than there is in readingfrom it. Reading from the persistent store is relatively fast while commits are relatively slow.

Best practice: Using efficient data structure selection

Data structure selection defines how many object handles and how much flash memory a BlackBerry® Java Application consumes.Improper data structure selection can consume key resources without improving the BlackBerry Java Application functionalityor the BlackBerry device user experience.

Development Guide Performance of the persistent store

40

Page 43: Blackberry Java SDK Development Guide

Consider the following guidelines:

• The data structure should consist of the least possible number of objects, especially when you use high-level objects like aVector or a Hashtable. These classes provide significant functionality but are not efficient storage mechanisms andyou should avoid using them in the persistent store if possible.

• When possible, use primitives instead of objects, because primitives reduce the number of object handles that are consumedon the BlackBerry device. An array of primitives is an object and consumes an object handle.

• String objects are as efficient as byte arrays. A String object consumes only one object handle and is equivalent if yourapplication stores all of the characters as a byte. In other words, the value of each character is less than or equal to thedecimal value of 255. If your application cannot store characters as a byte, you can store the characters as a String, whichis equivalent to storing a char array.

Best practice: Conserving object handles

One of the most common errors that application developers encounter is an exhaustion of persistent object handles. The amountof application storage space on the BlackBerry® device determines the fixed number of persistent object handles that are availablein the system. Depending on the data structure selection, stored records can quickly exhaust the number of persistent objecthandles. A persistent object consumes a persistent object handle and an object handle. A transient object consumes only anobject handle.

For example, a record that contains ten String fields, which represent items such as a name, a phone number, and an address,consumes 11 persistent object handles, one for the record object and one for each String. If an application persists 3000records, the application consumes 33,000 persistent object handles, which exceeds the number of persistent object handlesavailable on a BlackBerry device with 16 MB of flash memory.

You can use the net.rim.device.api.system.ObjectGroup class to consolidate the object handles for an object intoone group. Using the example in the previous paragraph, if you group the record, the record consumes one persistent objecthandle instead of 11. The object handles for the String fields consolidate under the record object handle.

When you consolidate object handles into one group, the object handle is read-only. You must ungroup the object before youcan change it. After you complete the changes, group the object again. If you attempt to change a grouped object without firstungrouping it, an ObjectGroupReadOnlyException is thrown.

Ungrouping an object has a performance impact. The system creates a copy of the grouped object and allocates handles to eachof the objects inside that group. Therefore, objects should only be ungrouped when necessary.

It is possible for commits to the persistent store to occur during garbage collection without an explicit commit(), so groupingof objects should always occur before calls to setContents() or commit(). For more information about object grouping,see net.rim.device.api.system.ObjectGroup .

Development Guide Performance of the persistent store

41

Page 44: Blackberry Java SDK Development Guide

Cleanup of persistent objects

When an application is removed from a BlackBerry® device, persistent objects that are defined within the application areautomatically deleted. This is because each persistent object has a class type that is defined in the application. When theapplication is removed, the class type is deleted, so the persistent objects are deleted.

To ensure cleanup of the persistent storage you use, you should always store your instances of your own classes or your ownextensions of provided classes.

Creating a persistent storeTo create a persistent store, you create at least one PersistentObject. Each PersistentObject has a unique key oftype long.

Create a persistent data storeEach PersistentObject has a unique long key.

1. Import the required classes and interfaces.

import net.rim.device.api.system.PersistentObject;import net.rim.device.api.system.PersistentStore;import java.lang.String;import net.rim.device.api.ui.component.Dialog;

2. To create a unique long key, in the BlackBerry® Integrated Development Environment, type a string value. For exmaple,com.rim.samples.docs.userinfo

3. Right-click the string and click Convert ‘com.rim.samples.docs.userinfo’ to long.

4. Include a comment in your code to indicate the string that you used to generate the unique long key.

5. To create a persistent data store, create a single static PersistentObject and invokePersistentStore.getPersistentObject, using the unique long key as a parameter.

static PersistentObject store;static {store = PersistentStore.getPersistentObject( 0xa1a569278238dad2L );}

Store persistent data1. Import the required classes and interfaces.

Development Guide Creating a persistent store

42

Page 45: Blackberry Java SDK Development Guide

import net.rim.device.api.system.PersistentObject;import net.rim.device.api.system.PersistentStore;

2. Invoke setContents() on a PersistentObject. This method replaces the existing content with the new content.

3. To save the new content to the persistent store, invoke commit().

String[] userinfo = {username, password};synchronized(store) {store.setContents(userinfo); store.commit();}

4. To use a batch transaction to commit objects to the persistent store, invoke PersistentStore.getSynchObject(). This method retrieves the persistent store monitor that locks the object.

a. Synchronize on the object.

b. Invoke commit() as necessary. If any commit in the batch fails, the entire batch transaction fails.

5. To commit a monitor object separately from a batch transaction, invoke forceCommit() while synchronizing the monitorobject.

Store an object in a batch transaction1. To use a batch transaction to commit objects to the persistent store, invoke PersistentStore.getSynchObject

(). This method retrieves the persistent store monitor that locks the object.

2. Synchronize on the object.

3. Invoke commit() as necessary. If any commit in the batch fails, the entire batch transaction fails.

Working with the persistent storeYou can retrieve and remove objects and collections from the persistent store.

Retrieve persistent data1. Import the required classes and interfaces.

import net.rim.device.api.system.PersistentObject;import net.rim.device.api.ui.component.Dialog;

2. Invoke getContents() on a PersistentObject.

3. To convert to your desired format, perform an explicit cast on the object that PersistentObject.getContents()returns.

Development Guide Working with the persistent store

43

Page 46: Blackberry Java SDK Development Guide

synchronized(store) {String[] currentinfo = (String[])store.getContents(); if(currentinfo == null) {Dialog.alert(_resources.getString(APP_ERROR));} else {currentusernamefield.setText(currentinfo[0]);currentpasswordfield.setText(currentinfo[1]);}}

Remove persistent dataIf you delete the .cod file that defines a PersistentStore, then all persistent objects that the .cod file created are deleted.

1. Import the required classes and interfaces.

import net.rim.device.api.system.PersistentObject;import net.rim.device.api.system.PersistentStore;

2. To remove all persistent data from a BlackBerry® device application, invokePersistentStore.destroyPersistentObject(), providing as a parameter a unique key for thePersistentObject.

3. To remove individual data, treat the data as normal objects, and remove references to it. A garbage collection operationremoves the data.

Remove specific persistent data from a BlackBerry Java ApplicationTo delete individual data, treat the data as normal objects, and remove references to it. A garbage collected operationremoves the data.

Retrieve a collection from persistent storage1. Import the required classes and interfaces.

import java.util.Vector;import net.rim.device.api.system.PersistentStore;import net.rim.device.api.synchronization.SyncCollection;

2. To provide the BlackBerry® device application with access to the newest SyncCollection data from thePersistentStore, invoke the PersistentStore.getPersistentObject() method using the ID of theSyncCollection.

private PersistentObject _persist; private Vector _contacts; private static final long PERSISTENT_KEY = 0x266babf899b20b56L;_persist = PersistentStore.getPersistentObject( PERSISTENT_KEY );

Development Guide Working with the persistent store

44

Page 47: Blackberry Java SDK Development Guide

3. Store the returned data in a vector object.

_contacts = (Vector)_persist.getContents();

4. Create a method to provide the BlackBerry device application with the newest SyncCollection data before a wirelessdata backup session begins.

public void beginTransaction(){_persist = PersistentStore.getPersistentObject(PERSISTENT_KEY); _contacts = (Vector)_persist.getContents();}

5. Create code to manage the case where the SyncCollection you retrieve from the PersistentStore is empty.

if( _contacts == null ){_contacts = new Vector();_persist.setContents( _contacts );_persist.commit();}

Development Guide Working with the persistent store

45

Page 48: Blackberry Java SDK Development Guide

Storing objects nonpersistently 5

The runtime store provides a central location for applications to store and share information on a BlackBerry® device. Data inthe runtime store is not saved when the BlackBerry device is restarted. The RuntimeStore API was introduced with BlackBerry®Device Software 3.6.

The runtime store is implemented in the net.rim.device.api.system.RuntimeStore class.

Objects are stored using a key-value pair. When you store an object in the runtime store, you assign the object a unique ID oftype long and later use the ID to retrieve the object from the store. You can generate the unique ID in the Eclipse® editor byright-clicking the fully-qualified class name and clicking Convert 'name' to long.

Note: Before your application closes, remove objects from the runtime store that your application no longer requires. If you addan object instance to the runtime store and don't remove it, you could create a memory leak.

Common uses of the runtime storeYou can use the runtime store to store any object, and you can retrieve the object from a different process or a different application.You can also restrict access to data.

Here are some common uses of the runtime store:

Share data between two

applications

For example, an application suite could be made up of multiple applications, all of which use

data that is pushed to the device. One of the applications receives all the push data and

shares it with the other applications by temporarily storing the data in the runtime store.

The runtime store could also be used to set up communication between a listener (such as

a PushListener) and a running application.

Store a reference to an object

for later use

For example, an application that allows a BlackBerry device user to add and remove an

ApplicationMenuItem could use the runtime store to store a reference to an

ApplicationMenuItem it has registered. After the application is closed and re-opened,

the ApplicationMenuItem can be accessed and unregistered.

Implement system-wide

singletons

An application might require one or more singleton objects to be accessed from within the

application itself or by other applications.

Security of the runtime storeBy default, only BlackBerry® device applications that Research In Motion digitally signs can access data in the runtime store.

Development Guide Storing objects nonpersistently

46

Page 49: Blackberry Java SDK Development Guide

Protect runtime store data using code signing keys1. Import the required classes and interfaces.

import java.util.Hashtable;import net.rim.device.api.system.RuntimeStore;

2. Create a hash ID for the object you want to store in the runtime store.

long MY_DATA_ID = 0x33abf322367f9018L;Hashtable myHashtable = new Hashtable();

3. Store the object in the runtime store and protect the object with the CodeSigningKey object. Only applications signedwith the key can read or change the object.

RuntimeStore.put( MY_DATA_ID, new ControlledAccess( myHashtable, key ) );

4. Make sure that the object is protected with a particular code signing key, and invoke RuntimeStore.get, providing asparameters the hash ID for the object and the CodeSigningKey object.

Add an object to the runtime store1. Invoke RuntimeStore.put(long, String) and provide as parameters a unique long ID and the runtime object to

store.

2. Create a try/catch block to manage the IllegalArgumentException that put() throws if a runtime object with thesame ID exists.

RuntimeStore store = RuntimeStore.getRuntimeStore();String msg = "Some shared text";long ID = 0x60ac754bc0867248L;try {store.put( ID, msg );} catch(IllegalArgumentException e) {}

Replace an object in the runtime store1. Invoke replace().

2. Create a try/catch block to manage the ControlledAccessException that replace() throws if the runtime objectwith the specified ID does not exist.

RuntimeStore store = RuntimeStore.getRuntimeStore();String newmsg = "Some new text";try {

Development Guide Add an object to the runtime store

47

Page 50: Blackberry Java SDK Development Guide

Object obj = store.replace( 0x60ac754bc0867248L, newmsg);} catch(ControlledAccessException e) {} not exist.

Retrieve the runtime store1. Import the required classes and interfaces.

import java.lang.IllegalArgumentException;import java.lang.RuntimeException;import java.lang.String;import net.rim.device.api.system.ControlledAccessException;import net.rim.device.api.system.RuntimeStore;import net.rim.device.api.util.ListenerUtilities;

2. Invoke RuntimeStore.getRuntimeStore().

RuntimeStore store = RuntimeStore.getRuntimeStore();

Retrieve a registered runtime object1. Invoke RuntimeStore.get() and provide as a parameter the runtime object ID.

2. Create a try/catch block to manage the ControlledAccessException that get() throws if the application doesnot have read access to the specified runtime object.

RuntimeStore store = RuntimeStore.getRuntimeStore();try {Object obj = store.get(0x60ac754bc0867248L);} catch(ControlledAccessException e) {}

Retrieve an unregistered runtime object1. Invoke RuntimeStore.waitFor() to wait for registration of a runtime object to complete. If the runtime object with

the specified ID does not exist, waitFor() blocks for a maximum of MAX_WAIT_MILLIS.

2. Create code for handling exceptions.

RuntimeStore store = RuntimeStore.getRuntimeStore();try {Object obj = store.waitFor(0x60ac754bc0867248L);} catch(ControlledAccessException e) {} catch(RuntimeException e) {}

Development Guide Retrieve the runtime store

48

Page 51: Blackberry Java SDK Development Guide

Code sample: Storing a String in the runtime storeFor simplicity, this example does not show how to create the unique ID.

import net.rim.device.api.system.Application;import net.rim.device.api.system.RuntimeStore;

public class RuntimeSet extends Application { public static void main(String[] args) { RuntimeSet app = new RuntimeSet(); System.exit(0); }

public RuntimeSet() { RuntimeStore rts = RuntimeStore.getRuntimeStore(); long ID = 0x60ac754bc0867248L; //just a unique ID - generate any way you want rts.put(ID, "Shared Message"); }}

Code sample: Getting a stored String from the runtime storeFor simplicity, this example does not show how to create the unique ID.

import net.rim.device.api.system.RuntimeStore;import net.rim.device.api.ui.UiApplication;import net.rim.device.api.ui.component.Dialog;import net.rim.device.api.ui.component.LabelField;import net.rim.device.api.ui.container.MainScreen;

public class RuntimeGet extends UiApplication { public static void main(String[] args) { RuntimeGet app = new RuntimeGet(); app.enterEventDispatcher(); } public RuntimeGet() { RuntimeStore rts = RuntimeStore.getRuntimeStore(); long ID = 0x60ac754bc0867248L; //just a unique ID - generate any way you want String msg = (String)rts.get(ID); pushScreen(new HomeScreen(msg));

Development Guide Code sample: Storing a String in the runtime store

49

Page 52: Blackberry Java SDK Development Guide

}

}

class HomeScreen extends MainScreen{ public HomeScreen(String msg) { add(new LabelField(msg)); }}

Code sample: Creating a singleton using the RuntimeStore APIThe following example creates a singleton using the runtime store. In this example, the static variable _instance is initializedto null for each process running on the system, so getInstance() must check the _instance variable each time it is invoked.

For simplicity, this example does not show how to create the unique ID.

import net.rim.device.api.system.*;

class MySingleton { private static MySingleton _instance; private static final long GUID = 0xab4dd61c5d004c18L;

// constructor MySingleton() {}

public static MySingleton getInstance() { if (_instance == null) { _instance = (MySingleton)RuntimeStore.getRuntimeStore().get(GUID); if (_instance == null) { MySingleton singleton = new MySingleton();

RuntimeStore.getRuntimeStore().put(GUID, singleton); _instance = singleton; } }

return _instance;

}}

Development Guide Code sample: Creating a singleton using the RuntimeStore API

50

Page 53: Blackberry Java SDK Development Guide

Storing data in the record store 6

The MIDP specification provides persistent storage for MIDlets. This mechanism is called the MIDP Record Management System(RMS), or record store. It is modeled after a simple record-oriented database. The record store is the MIDP equivalent of the RIMPersistentStore API and is available on all MIDP devices.

The RMS API is implemented in the javax.microedition.rms class.

While it is designed for MIDlets, the record store can also be used in BlackBerry® device applications.

The record store provides a simple record management system that allows you to create a data store object and persist a seriesof records within that object. Each record is a byte array, so you must serialize your data into a byte array format before storingit locally. Each byte array is assigned an integer ID that you use later to retrieve the byte array. Retrieval is done by enumeratingover the records. The RMS API does not provide any inherent indexing or relationships between records.

Applications that use the record store can either make data private or allow sharing. The record store is frequently used to sharedata between applications.

Data that an application saves in a record store is automatically deleted when the application is removed. When you upgrade anapplication that uses the record store, the data is retained.

Here are the maximum storage sizes for the record store:

BlackBerry® Device Software version Maximum individual record store size Maximum total record store size

(cumulative for all applications)

Earlier than 4.1 64 KB 64 KB

4.1 to 4.5 64 KB Available device memory

4.6 or later 512 KB Available device memory

Create a record store1. Import the javax.microedition.rms.RecordStore class.

2. Invoke openRecordStore(), and specify true to indicate that the method should create the record store if the recordstore does not exist.

RecordStore store = RecordStore.openRecordStore("Contacts", true);

Add a record to a record store1. Import the javax.microedition.rms.RecordStore class.

Development Guide Storing data in the record store

51

Page 54: Blackberry Java SDK Development Guide

2. Invoke addRecord().

int id = store.addRecord(_data.getBytes(), 0, _data.length());

Code sample: Adding a record to the record storeThe following code sample shows you how to add a byte array using the RMS API.

int authMode = RecordStore.AUTHMODE_ANY;boolean bWrite = true;

rs = RecordStore.openRecordStore( "rs", true, authMode, bWrite ); byte[] pi = new byte[]{ 3, 1, 4, 1, 5, 9 };int recordID;

recordID = rs.addRecord(pi, 0, pi.length);

Retrieve a record from a record store1. Import the required classes and interfaces.

import java.lang.String;import javax.microedition.rms.RecordStore;

2. Invoke getRecord(int, byte[], int). Pass the following parameters:• a record ID• a byte array• an offset

byte[] data = new byte[store.getRecordSize(id)];store.getRecord(id, data, 0);String dataString = new String(data);

Retrieve all records from a record store1. Import the required classes and interfaces.

import javax.microedition.rms.RecordComparator;import javax.microedition.rms.RecordEnumeration;import javax.microedition.rms.RecordFilter;import javax.microedition.rms.RecordStore;

2. Invoke openRecordStore().

Development Guide Retrieve a record from a record store

52

Page 55: Blackberry Java SDK Development Guide

3. Invoke enumerateRecords(). Pass the following parameters:• filter: specifies a RecordFilter object to retrieve a subset of record store records (if null, the method returns all

records)• comparator: specifies a RecordComparator object to determine the order in which the method returns the records

(if null, the method returns the records in any order)• keepUpdated: determines if the method keeps the enumeration current with the changes to the record store

RecordStore store = RecordStore.openRecordStore("Contacts", false);RecordEnumeration e = store.enumerateRecords(null, null, false);

Code sample: Storing and retrieving data with the record storeThis example uses the RMS API to store and retrieve high scores for a game. In the example, high scores are stored in separaterecords, and sorted when necessary using a RecordEnumeration.

import javax.microedition.rms.*;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.EOFException;import java.io.IOException;

/** * A class used for storing and showing game scores. */public class RMSGameScores implements RecordFilter, RecordComparator{ /* * The RecordStore used for storing the game scores. */ private RecordStore recordStore = null;

/* * The player name to use when filtering. */ public static String playerNameFilter = null;

/* * Part of the RecordFilter interface. */ public boolean matches(byte[] candidate) throws IllegalArgumentException { // If no filter set, nothing can match it. if (this.playerNameFilter == null) { return false;

Development Guide Code sample: Storing and retrieving data with the record store

53

Page 56: Blackberry Java SDK Development Guide

}

ByteArrayInputStream bais = new ByteArrayInputStream(candidate); DataInputStream inputStream = new DataInputStream(bais); String name = null;

try { int score = inputStream.readInt(); name = inputStream.readUTF(); } catch (EOFException eofe) { System.out.println(eofe); eofe.printStackTrace(); } catch (IOException eofe) { System.out.println(eofe); eofe.printStackTrace(); } return (this.playerNameFilter.equals(name)); }

/* * Part of the RecordComparator interface. */ public int compare(byte[] rec1, byte[] rec2) { // Construct DataInputStreams for extracting the scores from // the records. ByteArrayInputStream bais1 = new ByteArrayInputStream(rec1); DataInputStream inputStream1 = new DataInputStream(bais1); ByteArrayInputStream bais2 = new ByteArrayInputStream(rec2); DataInputStream inputStream2 = new DataInputStream(bais2); int score1 = 0; int score2 = 0; try { // Extract the scores. score1 = inputStream1.readInt(); score2 = inputStream2.readInt(); } catch (EOFException eofe) { System.out.println(eofe); eofe.printStackTrace(); } catch (IOException eofe) { System.out.println(eofe); eofe.printStackTrace(); }

// Sort by score if (score1 < score2) { return RecordComparator.PRECEDES; }

Development Guide Code sample: Storing and retrieving data with the record store

54

Page 57: Blackberry Java SDK Development Guide

else if (score1 > score2) { return RecordComparator.FOLLOWS; } else { return RecordComparator.EQUIVALENT; } }

/** * The constructor opens the underlying record store, * creating it if necessary. */ public RMSGameScores() { // // Create a new record store for this example // try { recordStore = RecordStore.openRecordStore("scores", true); } catch (RecordStoreException rse) { System.out.println(rse); rse.printStackTrace(); } }

/** * Add a new score to the storage. * * @param score the score to store. * @param playerName the name of the play achieving this score. */ public void addScore(int score, String playerName) { // // Each score is stored in a separate record, formatted with // the score, followed by the player name. // ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(baos); try { // Push the score into a byte array. outputStream.writeInt(score); // Then push the player name. outputStream.writeUTF(playerName); } catch (IOException ioe) { System.out.println(ioe); ioe.printStackTrace(); }

// Extract the byte array

Development Guide Code sample: Storing and retrieving data with the record store

55

Page 58: Blackberry Java SDK Development Guide

byte[] b = baos.toByteArray(); // Add it to the record store try { recordStore.addRecord(b, 0, b.length); } catch (RecordStoreException rse) { System.out.println(rse); rse.printStackTrace(); } }

/** * A helper method for the printScores methods. */ private void printScoresHelper(RecordEnumeration re) { try { while(re.hasNextElement()) { int id = re.nextRecordId(); ByteArrayInputStream bais = new ByteArrayInputStream(recordStore.getRecord(id)); DataInputStream inputStream = new DataInputStream(bais); try { int score = inputStream.readInt(); String playerName = inputStream.readUTF(); System.out.println(playerName + " = " + score); } catch (EOFException eofe) { System.out.println(eofe); eofe.printStackTrace(); } } } catch (RecordStoreException rse) { System.out.println(rse); rse.printStackTrace(); } catch (IOException ioe) { System.out.println(ioe); ioe.printStackTrace(); } }

/** * This method prints all of the scores sorted by game score. */ public void printScores() { try { // Enumerate the records using the comparator implemented // above to sort by game score. RecordEnumeration re = recordStore.enumerateRecords(null, this,

Development Guide Code sample: Storing and retrieving data with the record store

56

Page 59: Blackberry Java SDK Development Guide

true); printScoresHelper(re); } catch (RecordStoreException rse) { System.out.println(rse); rse.printStackTrace(); } }

/** * This method prints all of the scores for a given player, * sorted by game score. */ public void printScores(String playerName) { try { // Enumerate the records using the comparator and filter // implemented above to sort by game score. RecordEnumeration re = recordStore.enumerateRecords(this, this, true); printScoresHelper(re); } catch (RecordStoreException rse) { System.out.println(rse); rse.printStackTrace(); } }

public static void main(String[] args) { RMSGameScores rmsgs = new RMSGameScores(); rmsgs.addScore(100, "Megan"); rmsgs.addScore(120, "Enrico"); rmsgs.addScore(80, "Andrea"); rmsgs.addScore(40, "Stephen"); rmsgs.addScore(200, "Sherisse"); rmsgs.addScore(110, "Acheson"); rmsgs.addScore(220, "Acheson"); System.out.println("All scores"); rmsgs.printScores(); System.out.println("Acheson's scores"); RMSGameScores.playerNameFilter = "Acheson"; rmsgs.printScores("Acheson"); }}

Development Guide Code sample: Storing and retrieving data with the record store

57

Page 60: Blackberry Java SDK Development Guide

Managing data 7

The BlackBerry® Java® Virtual Machine manages memory usage on the BlackBerry device. The BlackBerry JVM allocates memory,performs garbage collection, and automatically swaps data between random access memory and application storage.

BlackBerry® Device Software provides a number of tools to help you manage data in your applications. These tools provide waysto back up data, remove sensitive data, remove data that is no longer needed, and free up memory when needed.

Best practice: Minimizing memory useTo minimize runtime memory, consider the following guidelines:

• Use primitive types (such as int or Boolean) instead of objects (such as String or Integer).• Do not depend entirely on the garbage collector.• Avoid creating many objects quickly.• Set object references to null when you are finished using them.• Reuse objects as much as possible.• Move heavy processing to the server. For example, you can filter or sort data before sending it to the BlackBerry® device.

Removing sensitive dataThe memory cleaner can delete sensitive data that is stored in memory on a BlackBerry® device. Specific events trigger thememory cleaner to clear various caches and perform secure garbage collection. The memory cleaner is not on by default, but isturned on automatically when you enable encryption. To manually turn on the memory cleaner, the device user clicks Options> Security Options > Advanced Security Options > Memory Cleaning and sets the status to Enabled.

The Memory Cleaner API is implemented in the net.rim.device.api.memorycleaner package.

Users can configure which events trigger a memory cleaning. You can register your application to be notified if one of thoseevents occurs. To do so, implement the MemoryCleanerListener interface and register it using one of the static methodsMemoryCleanerDaemon.addListener() or MemoryCleanerDaemon.addWeakListener().

The MemoryCleanerListener interface has two methods, cleanNow() and getDescription(). The cleanNow() methodis invoked by the memory cleaner when a user configurable event occurs. The memory cleaner passes an event parameter whenit calls cleanNow() to indicate the event that initiated the memory clean request. The getDescription() method isinvoked by the memory cleaner if the memory cleaner must display information about the applications that are registered cleaners.This functionality is required, for example, on the Memory Cleaning option screen.

Development Guide Managing data

58

Page 61: Blackberry Java SDK Development Guide

Using the Garbage CollectorThe BlackBerry® Java® Virtual Machine includes the Garbage Collector, which runs periodically to remove unreferenced andweakly referenced objects from memory. Do not call the Garbage Collector directly, but release resources by setting their referenceto null after use.

Full garbage collection on a BlackBerry device

The full garbage collection operation executes for 1 second on average and should take less than 2 seconds to complete. The fullgarbage collection operation performs the following actions:

• It performs a RAM garbage collection operation.• It marks objects in flash memory that are no longer referenced or no longer persisted.• It releases any nonpersistent object handles in RAM and flash memory.

The system might initiate a full garbage collection operation in the following situations:

• The BlackBerry® Java® Virtual Machine cannot allocate an object because of a lack of available space in RAM.• A process is about to exceed its currently allocated heap size.• The BlackBerry JVM cannot allocate a new object because the object handles are not available.• The BlackBerry device is idle.

RAM garbage collection on a BlackBerry device

The BlackBerry® Java® Virtual Machine initiates a RAM garbage collection operation only when the BlackBerry JVM cannotallocate an object because of a lack of space in RAM. The RAM garbage collection operation typically takes 500 to 600 millisecondsto execute. The garbage collection operation removes any freshly allocated variables that are no longer referenced in RAM. Tomake sure that the lack of a reference in RAM is a sufficient condition for removing the object, a RAM garbage collection operationcan only be performed when objects have not been paged out to flash memory.

Idle garbage collection on a BlackBerry device

Garbage collection does not occur every time the BlackBerry® device idles. It occurs only when the system considers a garbagecollection operation to be beneficial for optimal system performance and maximized battery performance.

To improve performance without impacting the BlackBerry device user experience, the system attempts to perform the followinggarbage collection operations when the BlackBerry device idles:

• A full garbage collection operation can occur when the BlackBerry device idles for a relatively short period of time.• A thorough garbage collection operation can occur when the BlackBerry device idles for a significant period of time.

Development Guide Using the Garbage Collector

59

Page 62: Blackberry Java SDK Development Guide

Managing low memoryWhen the available memory on a BlackBerry® device falls below the threshold that the device requires to function correctly, theLow Memory Manager attempts to make more memory available. The Low Memory Manager prioritizes objects in memory andmarks the less critical objects for deletion by the BlackBerry® Java® Virtual Machine. Opened messages and older calendarentries are typically deleted first.

The Low Memory Manager API is implemented in net.rim.device.api.lowmemory .

You should design your application to work with the Low Memory Manager to make available as much memory as possible whenthe device is low on memory resources. To do so, implement the LowMemoryListener interface and register it with the LowMemory Manager by calling the static LowMemoryManager.addLowMemoryListener() method.

The LowMemoryListener interface has a single method, freeStaleObject(), that is invoked by the Low MemoryManager when it needs to make memory available. When it invokes freeStaleObject(), the Low Memory Manager passesa priority parameter to indicate that it is initiating a high, medium, or low memory recovery request. Be careful to return truefrom freeStaleObject() if you freed any resources and false otherwise. This is important because the Low MemoryManager needs an accurate accounting of the memory freeing progress.

Identifying low memory availability on a BlackBerry device

The following conditions can cause the Low Memory Manager to attempt to free memory resources:

• The amount of available memory on the BlackBerry® device falls below a certain threshold. The threshold depends on theamount of free RAM in the system. The memory threshold ranges from 400 KB to 800 KB.

• The number of persistent object handles that are available on the BlackBerry device falls below 1000.• The number of object handles that are available on the BlackBerry device falls below 1000.

Backing up dataThe BlackBerry® Device Manager provides a backup and restore tool that a BlackBerry device user can use to save BlackBerrydevice data to a file on a computer and to restore data to the BlackBerry device.

With the Synchronization API, you can create applications that integrate with the BlackBerry® Desktop Manager or BlackBerry®Enterprise Server to back up data from a BlackBerry device.

The Synchronization API is implemented in the net.rim.device.api.synchronization package.

When an application uses the Synchronization API, the BlackBerry Desktop Manager can back up and restore the applicationdatabase at the same time as other BlackBerry device databases. You can use the Synchronization API to create data archivesor to populate application databases the first time the BlackBerry device connects to the BlackBerry device user's computer.

Development Guide Managing low memory

60

Page 63: Blackberry Java SDK Development Guide

To synchronize data to remote data sources, you must build the synchronization logic into your application. Most applicationssend data to a server-side application using standard HTTP or TCP/IP protocols over the wireless network and the Internet oran intranet. You can use XML APIs to generate and parse XML-formatted data to send and receive over the wireless network.However, your client-side and server-side applications must read and write the data properly and acknowledge successfultransmission of the data.

Your BlackBerry device application might connect to an application on a computer to send the data over a USB connection withthe Synchronization API and the BlackBerry Desktop Manager. In this case, the desktop application must be able to read thedata from your BlackBerry device application through an add-in task for the BlackBerry Desktop Manager. The BlackBerry deviceuser must manually execute the synchronization by running the BlackBerry Desktop Manager add-in, which notifies theapplication on the BlackBerry device to send the data to the computer application. You can also write data to the desktopapplication using the native USB protocols.

To enable an application to back up data, you can implement the following Synchronization interfaces and use theSyncManager class to register your application for synchronization.

Interface Description

SyncConverter Converts data between the SyncObject format that is required on the BlackBerry device

and the serialized format that is required on the computer.

SyncCollection Represents the collection of synchronization objects for an application.

SyncObject Represents an object that can be backed up and restored.

The following sample applications are included with the BlackBerry® Java® Development Environment: SyncDemo,OTASyncDemo, and OTABackupRestoreDemo.

To back up and restore a small amount of data such as application configuration options, you do not have to implement all ofthese interfaces. Instead, you can extend the SyncItem class and implement its abstract methods. The SyncItem classimplements the SyncCollection, SyncConverter, and SyncObject interfaces for you. For more information, see Backupand restore small amounts of data using SyncItem.

Development Guide Backing up data

61

Page 64: Blackberry Java SDK Development Guide

Find more information 8

• www.blackberry.com/go/apiref: View the latest version of the API reference for the BlackBerry® Java® SDK.• www.blackberry.com/go/devguides: Find development guides, release notes, and sample application overviews for the

BlackBerry Java SDK.• www.blackberry.com/developers: Visit the BlackBerry® Developer Zone for resources on developing BlackBerry device

applications.• www.blackberry.com/go/developerkb: View knowledge base articles on the BlackBerry Development Knowledge Base.• www.blackberry.com/developers/downloads: Find the latest development tools and downloads for developing BlackBerry

device applications.

Development Guide Find more information

62

Page 65: Blackberry Java SDK Development Guide

Provide feedback 9

To provide feedback on this deliverable, visit www.blackberry.com/docsfeedback.

Development Guide Provide feedback

63

Page 66: Blackberry Java SDK Development Guide

Glossary 10

application storageApplication storage is internal to the BlackBerry device. It contains the operating system, BlackBerry® JVM, and an internalfile system. Application storage is also known as flash memory and onboard memory. Applications on a BlackBerry devicecan be run only from the application storage. All BlackBerry devices have application storage.

built-in media storageBuilt-in media storage is a storage location on an eMMC. It is not removable. A FAT file system is mounted on the built-inmedia card. Built-in media storage is also called internal media memory and onboard device memory.

eMMCembedded MultiMediaCard

FATFile Allocation Table

flash memoryThe flash memory is an internal file system on a BlackBerry device that stores application data and user data.

JSRJava® Specification Request

media card storageMedia card storage is a storage location on a microSD card that a BlackBerry device user can use to extend the amount ofstorage on a device. The media card storage is optional and removable. A FAT file system is mounted on the media card.

MIDPMobile Information Device Profile

persistent store in flash memoryThe persistent store in flash memory stores data for a BlackBerry device. By default, third-party applications cannot accessthe persistent store. When it deletes all device data, the BlackBerry device deletes the data in the persistent store.

RIM signing authority systemThe RIM® signing authority system is a collection of servers that sign the boot ROM code for a BlackBerry device during themanufacturing process.

SQLStructured Query Language

UTF-88-bit UCS/Unicode Transformation Format

Development Guide Glossary

64

Page 67: Blackberry Java SDK Development Guide

Document revision history 11

Date Description

29 November 2010 Added topic: Using foreign key constraints

26 November 2010 Widespread edits

16 August 2010 Initial version

Development Guide Document revision history

65

Page 68: Blackberry Java SDK Development Guide

Legal notice 12

©2010 Research In Motion Limited. All rights reserved. BlackBerry®, RIM®, Research In Motion®, and related trademarks, names,and logos are the property of Research In Motion Limited and are registered and/or used in the U.S. and countries around theworld.

Java is a trademark of Oracle America, Inc. SQLite is a trademark of Hipp, Wyrick & Company, Inc. All other trademarks are theproperty of their respective owners.

This documentation including all documentation incorporated by reference herein such as documentation provided or madeavailable at www.blackberry.com/go/docs is provided or made accessible "AS IS" and "AS AVAILABLE" and without condition,endorsement, guarantee, representation, or warranty of any kind by Research In Motion Limited and its affiliated companies("RIM") and RIM assumes no responsibility for any typographical, technical, or other inaccuracies, errors, or omissions in thisdocumentation. In order to protect RIM proprietary and confidential information and/or trade secrets, this documentation maydescribe some aspects of RIM technology in generalized terms. RIM reserves the right to periodically change information thatis contained in this documentation; however, RIM makes no commitment to provide any such changes, updates, enhancements,or other additions to this documentation to you in a timely manner or at all.

This documentation might contain references to third-party sources of information, hardware or software, products or servicesincluding components and content such as content protected by copyright and/or third-party web sites (collectively the "ThirdParty Products and Services"). RIM does not control, and is not responsible for, any Third Party Products and Services including,without limitation the content, accuracy, copyright compliance, compatibility, performance, trustworthiness, legality, decency,links, or any other aspect of Third Party Products and Services. The inclusion of a reference to Third Party Products and Servicesin this documentation does not imply endorsement by RIM of the Third Party Products and Services or the third party in any way.

EXCEPT TO THE EXTENT SPECIFICALLY PROHIBITED BY APPLICABLE LAW IN YOUR JURISDICTION, ALL CONDITIONS,ENDORSEMENTS, GUARANTEES, REPRESENTATIONS, OR WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDINGWITHOUT LIMITATION, ANY CONDITIONS, ENDORSEMENTS, GUARANTEES, REPRESENTATIONS OR WARRANTIES OFDURABILITY, FITNESS FOR A PARTICULAR PURPOSE OR USE, MERCHANTABILITY, MERCHANTABLE QUALITY, NON-INFRINGEMENT, SATISFACTORY QUALITY, OR TITLE, OR ARISING FROM A STATUTE OR CUSTOM OR A COURSE OF DEALINGOR USAGE OF TRADE, OR RELATED TO THE DOCUMENTATION OR ITS USE, OR PERFORMANCE OR NON-PERFORMANCEOF ANY SOFTWARE, HARDWARE, SERVICE, OR ANY THIRD PARTY PRODUCTS AND SERVICES REFERENCED HEREIN, AREHEREBY EXCLUDED. YOU MAY ALSO HAVE OTHER RIGHTS THAT VARY BY STATE OR PROVINCE. SOME JURISDICTIONSMAY NOT ALLOW THE EXCLUSION OR LIMITATION OF IMPLIED WARRANTIES AND CONDITIONS. TO THE EXTENTPERMITTED BY LAW, ANY IMPLIED WARRANTIES OR CONDITIONS RELATING TO THE DOCUMENTATION TO THE EXTENTTHEY CANNOT BE EXCLUDED AS SET OUT ABOVE, BUT CAN BE LIMITED, ARE HEREBY LIMITED TO NINETY (90) DAYS FROMTHE DATE YOU FIRST ACQUIRED THE DOCUMENTATION OR THE ITEM THAT IS THE SUBJECT OF THE CLAIM.

TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION, IN NO EVENT SHALL RIM BE LIABLEFOR ANY TYPE OF DAMAGES RELATED TO THIS DOCUMENTATION OR ITS USE, OR PERFORMANCE OR NON-PERFORMANCE OF ANY SOFTWARE, HARDWARE, SERVICE, OR ANY THIRD PARTY PRODUCTS AND SERVICES REFERENCEDHEREIN INCLUDING WITHOUT LIMITATION ANY OF THE FOLLOWING DAMAGES: DIRECT, CONSEQUENTIAL, EXEMPLARY,INCIDENTAL, INDIRECT, SPECIAL, PUNITIVE, OR AGGRAVATED DAMAGES, DAMAGES FOR LOSS OF PROFITS OR REVENUES,FAILURE TO REALIZE ANY EXPECTED SAVINGS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, LOSS OFBUSINESS OPPORTUNITY, OR CORRUPTION OR LOSS OF DATA, FAILURES TO TRANSMIT OR RECEIVE ANY DATA, PROBLEMS

Development Guide Legal notice

66

Page 69: Blackberry Java SDK Development Guide

ASSOCIATED WITH ANY APPLICATIONS USED IN CONJUNCTION WITH RIM PRODUCTS OR SERVICES, DOWNTIME COSTS,LOSS OF THE USE OF RIM PRODUCTS OR SERVICES OR ANY PORTION THEREOF OR OF ANY AIRTIME SERVICES, COST OFSUBSTITUTE GOODS, COSTS OF COVER, FACILITIES OR SERVICES, COST OF CAPITAL, OR OTHER SIMILAR PECUNIARYLOSSES, WHETHER OR NOT SUCH DAMAGES WERE FORESEEN OR UNFORESEEN, AND EVEN IF RIM HAS BEEN ADVISEDOF THE POSSIBILITY OF SUCH DAMAGES.

TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION, RIM SHALL HAVE NO OTHEROBLIGATION, DUTY, OR LIABILITY WHATSOEVER IN CONTRACT, TORT, OR OTHERWISE TO YOU INCLUDING ANY LIABILITYFOR NEGLIGENCE OR STRICT LIABILITY.

THE LIMITATIONS, EXCLUSIONS, AND DISCLAIMERS HEREIN SHALL APPLY: (A) IRRESPECTIVE OF THE NATURE OF THECAUSE OF ACTION, DEMAND, OR ACTION BY YOU INCLUDING BUT NOT LIMITED TO BREACH OF CONTRACT, NEGLIGENCE,TORT, STRICT LIABILITY OR ANY OTHER LEGAL THEORY AND SHALL SURVIVE A FUNDAMENTAL BREACH OR BREACHESOR THE FAILURE OF THE ESSENTIAL PURPOSE OF THIS AGREEMENT OR OF ANY REMEDY CONTAINED HEREIN; AND (B)TO RIM AND ITS AFFILIATED COMPANIES, THEIR SUCCESSORS, ASSIGNS, AGENTS, SUPPLIERS (INCLUDING AIRTIMESERVICE PROVIDERS), AUTHORIZED RIM DISTRIBUTORS (ALSO INCLUDING AIRTIME SERVICE PROVIDERS) AND THEIRRESPECTIVE DIRECTORS, EMPLOYEES, AND INDEPENDENT CONTRACTORS.

IN ADDITION TO THE LIMITATIONS AND EXCLUSIONS SET OUT ABOVE, IN NO EVENT SHALL ANY DIRECTOR, EMPLOYEE,AGENT, DISTRIBUTOR, SUPPLIER, INDEPENDENT CONTRACTOR OF RIM OR ANY AFFILIATES OF RIM HAVE ANY LIABILITYARISING FROM OR RELATED TO THE DOCUMENTATION.

Prior to subscribing for, installing, or using any Third Party Products and Services, it is your responsibility to ensure that yourairtime service provider has agreed to support all of their features. Some airtime service providers might not offer Internet browsingfunctionality with a subscription to the BlackBerry® Internet Service. Check with your service provider for availability, roamingarrangements, service plans and features. Installation or use of Third Party Products and Services with RIM's products and servicesmay require one or more patent, trademark, copyright, or other licenses in order to avoid infringement or violation of third partyrights. You are solely responsible for determining whether to use Third Party Products and Services and if any third party licensesare required to do so. If required you are responsible for acquiring them. You should not install or use Third Party Products andServices until all necessary licenses have been acquired. Any Third Party Products and Services that are provided with RIM'sproducts and services are provided as a convenience to you and are provided "AS IS" with no express or implied conditions,endorsements, guarantees, representations, or warranties of any kind by RIM and RIM assumes no liability whatsoever, in relationthereto. Your use of Third Party Products and Services shall be governed by and subject to you agreeing to the terms of separatelicenses and other agreements applicable thereto with third parties, except to the extent expressly covered by a license or otheragreement with RIM.

Certain features outlined in this documentation require a minimum version of BlackBerry® Enterprise Server, BlackBerry® DesktopSoftware, and/or BlackBerry® Device Software.

The terms of use of any RIM product or service are set out in a separate license or other agreement with RIM applicable thereto.NOTHING IN THIS DOCUMENTATION IS INTENDED TO SUPERSEDE ANY EXPRESS WRITTEN AGREEMENTS OR WARRANTIESPROVIDED BY RIM FOR PORTIONS OF ANY RIM PRODUCT OR SERVICE OTHER THAN THIS DOCUMENTATION.

Research In Motion Limited295 Phillip StreetWaterloo, ON N2L 3W8

Development Guide Legal notice

67

Page 70: Blackberry Java SDK Development Guide

Canada

Research In Motion UK Limited Centrum House 36 Station Road Egham, Surrey TW20 9LF United Kingdom

Published in Canada

Development Guide Legal notice

68