|
|||||||||
PREV NEXT | FRAMES NO FRAMES |
The data storage category contains data storage packages.
You can choose from a variety of approaches for storing, sharing, and managing your application data. This document is designed to help you choose which data storage option is best suited for your application and to help you get started implementing your data storage solution. It provides an overview of data storage options; describes each option in more detail; and then introduces some data management tools.
This document includes the following sections:
Different BlackBerry® devices support different types of memory. The following types of memory are possible on BlackBerry devices:
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 following table lists data storage options across the top, and compares some main features.
Features | File System | SQLite® | Persistent Store | MIDP RMS | Runtime Store |
---|---|---|---|---|---|
Data format that can be stored | Any; but is most useful for large read-only files | Relational database file | Java object | Serialized | Java object |
Storage locations | Might be possible on application storage, external media card, and built-in media storage | Might be possible on external media card and built-in media storage | Application storage | Application storage | Application storage |
Maximum limit | Size of partitions the user has access to | Size of partitions the user has access to | Available application storage | Differs according to version (see details) | Available application storage |
Compatibility (BlackBerry Device Software versions) | FileConnection API: 4.2 and later | 5.0 and later | All | All | 3.6 and later |
Persist across device restarts? | Yes | Yes | Yes | Yes | No |
Share data between applications? | Yes | Yes | Yes | Yes | Yes |
Considerations for choosing a data storage option
Packages: net.rim.device.api.io.file, javax.microedition.io.file
You can programmatically create and manage the files and folders on BlackBerry devices using the FileConnection API. The FileConnection 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 (GCF).
It is implemented in javax.microedition.io.file.*
and
its main component is the FileConnection
class.
Unlike other GCF connections, FileConnection
objects can
be successfully returned from the Connector.open()
method
without referencing an existing file or folder.
This behavior allows for the creation of new files and folders on a file system.
RIM provides the following extensions to the FileConnection API. They are in the
net.rim.device.api.io.file.*
package:
FileSystemJournal
and FileSystemJournalListener
classes allow detection of changes to the file system.
ExtendedFileConnection
class allows the encryption and protection of files.
There are two types of storage you can access: internal storage and external media card storage.
Internal storage is application storage or built-in media storage.
To access internal storage, use the path file:///store
. For example,
FileConnection fc = (FileConnection)Connector.open("file:///Store")
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 removed when your application is removed.
When a BlackBerry device is connected to a computer using USB, users can transfer files from external media card storage with Mass Storage mode or the BlackBerry® Desktop Manager.
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, the system partition is read/write.
You can access this partition with the path file:///system
.
Click for code sample: Displaying the path to the video folder using System.getProperty()
import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.LabelField; import net.rim.device.api.ui.container.MainScreen; 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); } } |
Click for code sample: Retrieving a list of mounted roots
import java.util.Enumeration; import javax.microedition.io.file.FileSystemRegistry; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.component.LabelField; import net.rim.device.api.ui.container.MainScreen; 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)); } } |
Click for code sample: Creating a file
import net.rim.device.api.system.Application; import javax.microedition.io.*; import javax.microedition.io.file.*; import java.io.IOException; 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) { System.out.println(ioe.getMessage() ); } } } |
Click for code sample: Creating a folder
import net.rim.device.api.system.Application; import javax.microedition.io.*; import javax.microedition.io.file.*; import java.io.IOException; public class CreateFolderApp extends Application { 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, then the URI is valid, but the folder may or 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() ); } } } |
Click for code sample: Writing text to a file
import 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() ); } } } |
Click for code sample: Reading randomly-accessed sections of a file
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); } 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) { System.out.println( ioe.getMessage() ); } } } |
Package: net.rim.device.api.database
The Database API lets you create and use SQLite relational databases. The Database API was introduced with BlackBerry Device Software 5.0.
For more information about the Database API, see the Data Storage Development Guide.
BlackBerry Device Software 7.0 uses SQLite version 3.7.2.
Each SQLite database is stored in a single file.
If you specify only the database name as the parameter value to DatabaseFactory.create()
,
the database file is created on the external media card.
The default location for the database file is /SDCard/databases/application_name/
.
The name of the application that creates the database is included in the path to avoid name collisions.
You cannot store SQLite databases in application storage.
On devices that support built-in media storage, you can create database files in built-in media storage by specifying
the path /store/
.
For more information about SQLite, visit http://www.sqlite.org.
Click for code sample: Creating a SQLite database at the root of a media card
import net.rim.device.api.system.Application; import net.rim.device.api.database.*; import net.rim.device.api.io.*; public class CreateDatabase extends Application { public static void main(String[] args) { CreateDatabase app = new CreateDatabase(); try { URI strURI = URI.create("file:///SDCard/test.db"); DatabaseFactory.create(strURI); } catch ( Exception e ) { System.out.println( e.getMessage() ); } } } |
Click for code sample: Adding a table to a SQLite database
import net.rim.device.api.database.Database; import net.rim.device.api.database.DatabaseFactory; import net.rim.device.api.database.Statement; import net.rim.device.api.io.URI; import net.rim.device.api.system.Application; public class AddDatabaseTable extends Application { public static void main(String[] args) { AddDatabaseTable app = new AddDatabaseTable(); try { URI myURI = URI.create("/SDCard/test.db"); Database d = DatabaseFactory.open(myURI); Statement st = d.createStatement( "CREATE TABLE 'People' ( " + "'Name' TEXT, " + "'Age' INTEGER )" ); st.prepare(); st.execute(); st.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); } } } |
Click for code sample: Adding content to a SQLite table
import net.rim.device.api.database.Database; import net.rim.device.api.database.DatabaseFactory; import net.rim.device.api.database.Statement; import net.rim.device.api.io.URI; import net.rim.device.api.system.Application; public class AddDatabaseTable extends Application { public static void main(String[] args) { AddDatabaseTable app = new AddDatabaseTable(); try { URI myURI = URI.create("/SDCard/test.db"); Database d = DatabaseFactory.open(myURI); Statement st = d.createStatement("INSERT INTO People(Name,Age) " + "VALUES ('John',37)"); st.prepare(); st.execute(); st.close(); } catch ( Exception e ) { System.out.println( e.getMessage() ); } } } |
Package: net.rim.device.api.system
The Persistent Store API lets you save objects to persistent memory. The storage for each application is distinct because it uses 64-bit globally unique identifiers (GUIDs). The objects are retained in memory after a BlackBerry device restarts. The Persistent Store API is provided in all versions of BlackBerry Device Software.
Data is stored as instances of
PersistentObject
.
The contents of PersistentObject
can be any object that
implements the Persistable
interface.
In addition, the API allows the implicit persistence of classes;
the following data types automatically implement the Persistable
interface and so can be stored:
- 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
Cleanup
When an application is uninstalled, persistent objects that are defined within the application are automatically deleted. This is because each persistent object has a class type that is defined in the application. When the application is deleted 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 own extensions of provided classes.
Restricting access
If you want to permit only specific, authorized applications to access your application data,
then you should use the ControlledAccess
class in conjunction with
key generation and a key-signing procedure.
To restrict access to your data:
PersistentObject
in a ControlledAccess
object
that is associated with a signing key
that was created using the BlackBerry® Signing Authority Tool.For detailed instructions, see Protect persistent objects from access by unauthorized applications.
Conserving object handles
The persistent store's consumption of object handles can negatively affect performance.
You should consider using the grouping mechanism to persist objects and conserve handles.
Because it is possible for commits to the persistent store to occur during garbage collection,
without an explicit call to commit()
, grouping of objects should always occur before calls
to setContents()
or commit()
.
See net.rim.device.api.system.ObjectGroup
.
Package: javax.microedition.rms
The Mobile Information Device Profile (MIDP) specification provides persistent storage for MIDlets. This persistent storage mechanism is called the MIDP Record Management System (MIDP RMS). It is modeled after a simple record-oriented database. MIDP RMS is the MIDP equivalent of the RIM PersistentStore API. MIDP RMS is available on all MIDP devices. While designed for MIDlets, this storage method can also be used in BlackBerry applications.
The RMS API lets you store and retrieve byte arrays. Each byte array is assigned an integer ID that you use later to retrieve the byte array. Retrieval is done by enumerating over the records.
Applications that use the RMS API can either make data private or allow sharing. The RMS API is frequently used to share data between applications.
RMS data that an application saves is automatically deleted when the application is removed. When you upgrade an application that uses MIDP RMS data storage, the data is retained.
Here are the maximum storage sizes for RMS storage:
BlackBerry Device Software version | Maximum individual RecordStore size | Maximum total RecordStore 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 and later | 512 KB | Available device memory |
Click for code sample: Adding a byte array to the RMS store
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); |
Click for code sample: Storing and retrieving data with RMS store
import javax.microedition.rms.*; import java.io.DataOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.EOFException; /** * 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; } 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; } 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 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, 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, "Alice"); rmsgs.addScore(120, "Bill"); rmsgs.addScore(80, "Candice"); rmsgs.addScore(40, "Dean"); rmsgs.addScore(200, "Ethel"); rmsgs.addScore(110, "Farnsworth"); rmsgs.addScore(220, "Farnsworth"); System.out.println("All scores"); rmsgs.printScores(); System.out.println("Farnsworth's scores"); RMSGameScores.playerNameFilter = "Farnsworth"; rmsgs.printScores("Farnsworth"); } } |
Package: net.rim.device.api.system (Class RuntimeStore)
The runtime store provides a central location for applications to store and share information ona BlackBerry device. Data in the runtime store is not saved when the BlackBerry device is restarted. The RuntimeStore API was introduced with BlackBerry Device Software 3.6.
You 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.
Objects are stored using a key-value pair. When you store an object in the runtime store,
you assign the object a unique ID of type long
and later use the ID to retrieve
the object from the store.
Before you exit your application, remove objects from the runtime store that your applications no longer require.
Warning: You can create a memory allocation problem if you add an object instance to the runtime store and don't remove it. This is a common cause of memory leaks in BlackBerry applications. |
Here are some common uses for the runtime store:
PushListener
) and a running application.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.Click for code sample: Storing a String in the runtime store
For simplicity, this example does not show how to create the GUID.
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"); } } |
Click for code sample: Getting a stored String from the runtime store
For simplicity, this example does not show how to create the GUID.
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)); } } class HomeScreen extends MainScreen { public HomeScreen(String msg) { add(new LabelField(msg)); } } |
Click for code sample: Creating a singleton by using the RuntimeStore API
The following example creates a singleton using the runtime store.
In this example, the
static variable _instance
is initialized to 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 GUID.
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; } } |
Package: net.rim.device.api.synchronization
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.
To enable an application to back up data, implement the following
Synchronization interfaces and use the
SyncManager
class to register your application for synchronization.
Interface | Description |
---|---|
SyncConverter |
Converts data between the |
SyncCollection |
Represents the collection of synchronization objects for an application |
SyncObject
|
Represents an object that can be backed up and restored |
To download a sample application that demonstrates how to implement these interfaces, see the SyncDemo, OTASyncDemo, and OTABackupRestoreDemo code samples that are included with the BlackBerry® Java® Development Environment and the BlackBerry® Java® Plug-in for Eclipse®.
To back up and restore a small amount of data such as application configuration options,
you do not have to implement all of these interfaces.
Instead, you can extend the SyncItem
class and implement its abstract methods.
The SyncItem
class implements
the SyncCollection, SyncConverter,
and SyncObject
interfaces for you.
See Backup and restore small amounts of data using SyncItem.
Package: net.rim.device.api.lowmemory
BlackBerry devices require a minimum amount of memory to function properly. When available memory on a BlackBerry device falls below an acceptable threshold, the Low Memory Manager (LMM) attempts to provide more available memory resources. The LMM prioritizes objects in memory and marks the less critical objects for deletion by the JVM. Opened messages and older calendar entries are typically deleted first.
You should design your application to work with the LMM to make available as much memory
as possible when the device is low on memory resources.
To do so, implement the LowMemoryListener
interface and
register it with the LMM by calling the static LowMemoryManager.addLowMemoryListener()
method.
The LowMemoryListener
interface has a single method,
freeStaleObject()
, that is invoked by the LMM when it needs to make memory available.
When it invokes freeStaleObject()
, the LMM passes a priority parameter
to indicate that it is initiating a high, medium, or low memory recovery request.
Be careful to return true
from freeStaleObject()
if you freed any resources and false
otherwise.
This is important because the LMM needs an accurate accounting of the memory freeing progress.
Click for code sample: Implementing the freeStaleObject()
method
public boolean freeStaleObject( int priority ) { boolean dataFreed = false; switch( priority ) { case LowMemoryListener.HIGH_PRIORITY: dataFreed = freeVector( _data._high ); _priority = LowMemoryListener.LOW_PRIORITY; break; case LowMemoryListener.MEDIUM_PRIORITY: dataFreed = freeVector( _data._medium ); _priority = LowMemoryListener.HIGH_PRIORITY; break; case LowMemoryListener.LOW_PRIORITY: dataFreed = freeVector( _data._low ); _priority = LowMemoryListener.MEDIUM_PRIORITY; break; } if( dataFreed ) { _persist.commit(); } return dataFreed; } /** * A private method that frees the priority vector. * @param vector The vector to free. * @return A boolean that indicates whether any objects were freed by this * method. */ private boolean freeVector( Vector vector ) { boolean dataFreed = false; int size = vector.size(); for( int i = size - 1; i >= 0; i-- ) { Object obj = vector.elementAt( i ); vector.removeElementAt( i ); LowMemoryManager.markAsRecoverable( obj ); dataFreed = true; } return dataFreed; } |
Package: net.rim.device.api.memorycleaner
The memory cleaner can erase sensitive data that is stored in memory on a BlackBerry device. Specific events trigger it to clear various caches and perform secure garbage collection. The memory cleaner is not on by default. To turn it on, on the device click Options > Security Options > Advanced Security Options > Memory Cleaning and set Status to Enabled. The memory cleaner is turned on automatically when you enable encryption.
Users can configure which events trigger a memory cleaning.
You can register your application to be notified if one of those events occurs.
To do so, implement the MemoryCleanerListener
interface and register it using
one of the static methods MemoryCleanerDaemon.addListener()
or
MemoryCleanerDaemon.addWeakListener()
.
The interface has two methods, cleanNow()
and getDescription()
.
The cleanNow()
method is called by the memory cleaner when a user configurable event occurs.
The memory cleaner passes an event parameter when it calls cleanNow()
to indicate
the event that initiated the memory clean request.
The getDescription()
method is invoked by the memory cleaner if it must display information
about the applications that are registered cleaners.
This functionality is required, for example, on the Memory Cleaning option screen.
Click for code sample: Implementing and registering the MemoryCleanerListener interface
import net.rim.device.api.memorycleaner.*; import net.rim.device.api.system.Application; import net.rim.device.api.ui.component.Dialog; public class MemoryCleaner extends Application implements MemoryCleanerListener { public static void main(String[] args) { MemoryCleaner app = new MemoryCleaner(); app.enterEventDispatcher(); } public MemoryCleaner() { // if you don't use the second parameter to pass true, the cleaner will start immediately MemoryCleanerDaemon.addListener(this,false); } public boolean cleanNow(int event) { switch(event) { case MemoryCleanerListener.EVENT_DEVICE_LOCK: // if you free something // return true; // if you don't free anything return false; case MemoryCleanerListener.EVENT_IDLE_TIMEOUT: //if you free something //return true; // if you don't free anything return false; //add additional cases for any events you want to clean in response to } return false; } public String getDescription() { return "Sample Memory Cleaner"; } } |
Copyright 1999-2011 Research In Motion Limited. 295 Phillip Street, Waterloo, Ontario, Canada, N2L 3W8. All Rights Reserved. |
Legal |