BlackBerry 应用程序开发者指南 第二卷:高级--第9章 备份和恢复持久数据
作者:Confach 发表于 2006-04-28 22:28 pm
版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原始出处 和作者信息.
http://www.cnblogs.com/confach/articles/388968.html
9
第9章 备份和恢复持久数据
同步API 增加备份持久数据的支持 |
同步API
在net.rim.device.api.synchronization包里的同步API可以使应用程序和BlackBerry桌面软件集成以完成2个任务:
- 将一个数据库备份到桌面文件,以后可以恢复它.
- 和桌面应用程序同步数据.
Length<2> Type<1> Data<n>
为了验证数据是否有合适的格式,使用net.rim.device.api.synchronization.ConverterUtilities类里的任何一个写方法;
数据备份
桌面软件提供一个Backup and Restore工具,它允许用户将BlackBerry设备上的数据保存到桌面上的一个文件,并且使用此桌面文件将数据恢复到BlackBerry设备上.
当一个应用程序实现了同步API,桌面软件将应用程序数据库备份和恢复到其他的BlackBerry设备数据库.你也可以使用同步API创建数据备份(archives),或者当BlackBerry设备第一次连接到计算机时跳出应用程序数据库.
数据同步
桌面软件提供一个Intellisync的工具,此工具将BlackBerry设备和用户计算机上的应用程序同步.
当备份和恢复加载BlackBerry设备和一个桌面备份文件之间的数据时,同步比较桌面应用程序存在的数据和BlackBerry设备上的数据,然后合并这些数据..
为了和桌面应用程序进行数据同步,使用BlackBerry桌面API为桌面软件编写一个插件.BlackBerry JDE也包含了一个同步实例应用程序作为桌面的一个插件.
同步API
实现下面同步API提供的接口:
接口 |
描述 |
SyncConverter |
转化BlackBerry设备需要的SyncObject格式和桌面需要的序列化格式之间的数据. |
SyncCollection |
代表了一个应用程序同步对象的集合. |
SyncObject |
代表了一个可以备份和恢复到用户计算机的对象. |
SerialSyncManager类可以访问同步管理器,特别的,它可以为同步注册新的对象
增加备份持久数据的支持
为了支持备份,修改一个实现了Persistable接口的类,实现SyncObject接口.
修改应用程序的主类以实现SyncCollection和SyncConverter接口.
定义一个唯一ID
定义一个_uid变量. getUID()的实现为同步操作返回一个唯一ID.
定义一个构造子
你的构造子的实现接受一个唯一ID作为参数,并且将之设置为_uid变量的值.
注册一个同步集合
在main()方法里,在同步管理器上注册你的SyncCollection., 当BlackBerry设备第一次启动时,创建一个独立的工程传入初始化参数.为获的更多的信息,参看108页的”当BlackBery设备启动时注册一个同步集合”.
public static void main(String[] args) { boolean startup = false; for (int i=0; i<args.length; ++i) { if (args[i].startsWith("init")) { startup = true; } } if (startup) { //enable application for synchronization on startup SerialSyncManager.getInstance().enableSynchronization(new RestaurantsSync()); } else { RestaurantsSync app = new RestaurantsSync(); app.enterEventDispatcher(); } } |
当BlackBery设备启动时注册一个同步集合
当BlackBery设备启动时,为了注册一个同步集合, 为你的主要应用程序创建一个独立的工程来完成一个可选的入口.在BlackBerry第一次启动时,此工程传递一个参数到你的应用程序中,这样你的应用程序仅注册一次.
创建一个初始化工程
1.在BlackBerry IDE里,创建一个工程.
2.右击工程,点击Properties
3.单击Application标签.
4.在Project type 下拉列里, 点击Alternate CLDC Application Entry Point.
5.在Alternate entry point for的下拉列里, 单击实现同步的工程. 在Arguments passed to 域, 输入 init.
7.选择Auto-run on startup选项.
8.选择System module 选项.
9.单击OK.
代码实例
此代码实例描述如何使桌面软件为你的应用程序备份和恢复持久数据.此实例修改了Restaurants.java的代码,用来实现同步API.
/**
* RestaurantsSync.java
* Copyright (C) 2001-2005 Research In Motion Limited. All rights reserved.
*/
package com.rim.samples.docs.restaurantssync;
import java.io.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import net.rim.device.api.util.*;
import java.util.*;
import net.rim.device.api.i18n.*;
import net.rim.device.api.synchronization.*;
import com.rim.samples.docs.resource.*;
import com.rim.samples.docs.baseapp.*;
public class RestaurantsSync extends BaseApp
implements RestaurantsSyncResource,SyncCollection, SyncConverter,
KeyListener, TrackwheelListener {
private static final long KEY = 0xdec6a67096f833cL;
private AutoTextEditField namefield;
private AutoTextEditField addressfield;
private EditField phonefield;
private EditField specialtyfield;
private static PersistentObject store;
private static Vector _data;
private static ResourceBundle _resources;
private static final int FIELDTAG_NAME = 1;
private static final int FIELDTAG_PHONE = 2;
private static final int FIELDTAG_ADDRESS = 3;
private static final int FIELDTAG_SPECIALTY = 4;
private static RestaurantsSync _instance;
private MenuItem saveItem = new MenuItem(_resources, MenuItem.SAVE_CLOSE, 110, 10) {
public void run() {
RestaurantInfo info = new RestaurantInfo();
info.setElement(RestaurantInfo.NAME, namefield.getText());
info.setElement(RestaurantInfo.ADDRESS, addressfield.getText());
info.setElement(RestaurantInfo.PHONE, phonefield.getText());
info.setElement(RestaurantInfo.SPECIALTY, specialtyfield.getText());
_data.addElement(info);
synchronized(store) {
store.setContents(_data);
store.commit();
}
Dialog.inform(_resources.getString(APP_SUCCESS));
namefield.setText(null);
adressfield.setText(null);
phonefield.setText("");
specialtyfield.setText("");
}
};
private MenuItem getItem = new MenuItem("Get", 110, 11) {
public void run() {
synchronized(store) {
_data = (Vector)store.getContents();
if (!_data.isEmpty()) {
RestaurantInfo info = (RestaurantInfo)_data.lastElement();
namefield.setText(info.getElement(RestaurantInfo.NAME));
addressfield.setText(info.getElement(RestaurantInfo.ADDRESS));
phonefield.setText(info.getElement(RestaurantInfo.PHONE));
specialtyfield.setText(info.getElement(
RestaurantInfo.SPECIALTY));
}
}
}
};
static {
_resources = ResourceBundle.getBundle(RestaurantsSyncResource.BUNDLE_ID,
RestaurantsSyncResource.BUNDLE_NAME);
store = PersistentStore.getPersistentObject(KEY);
synchronized (store) {
_data = (Vector)store.getContents();
if ( _data == null )
{
data = new Vector();
store.setContents( _data );
store.commit();
}
}
}
public static void main(String[] args) {
boolean startup = false;
for (int i=0; i<args.length; ++i) {
if (args[i].startsWith("init"))
{
startup = true;
}
}
if (startup) {
// Enable application for synchronization on startup.
SyncManager.getInstance().enableSynchronization(
RestaurantsSync.getInstance());
}
else {
RestaurantsSync app = new RestaurantsSync();
app.enterEventDispatcher();
}
}
public static RestaurantsSync getInstance() {
if (_instance == null) {
_instance = new RestaurantsSync();
}
return _instance;
}
private static final class RestaurantInfo implements Persistable, SyncObject {
private String[] _elements; // Data.
public static final int NAME = 0;
public static final int ADDRESS = 1;
public static final int PHONE = 2;
public static final int SPECIALTY = 3;
private int _uid;
public int getUID() {
return _uid;
}
public RestaurantInfo() {
_elements = new String[4];
for ( int i = 0; i < _elements.length; ++i) {
_elements[i] = "";
}
}
public RestaurantInfo(int uid) {
_elements = new String[4];
for (int i = 0; i < _elements.length; ++i) {
_elements[i] = "";
}
_uid = uid;
}
public String getElement(int id) {
return _elements[id];
}
public void setElement(int id, String value) {
_elements[id] = value;
}
}
// SyncConverter methods.
public SyncObject convert(DataBuffer data, int version, int UID) {
try {
RestaurantInfo info = new RestaurantInfo(UID);
while(data.available() > 0) {
int length = data.readShort();
byte[] bytes = new byte[length];
switch (data.readByte()) {
case FIELDTAG_NAME:
data.readFully(bytes);
//trim null-terminator
info.setElement(RestaurantInfo.NAME,
new String(bytes).trim());
break;
case FIELDTAG_PHONE:
data.readFully(bytes);
info.setElement(RestaurantInfo.PHONE,
new String(bytes).trim());
break;
case FIELDTAG_ADDRESS:
data.readFully(bytes);
info.setElement(RestaurantInfo.ADDRESS,
new String(bytes).trim());
break;
case FIELDTAG_SPECIALTY:
data.readFully(bytes);
info.setElement(RestaurantInfo.SPECIALTY,
new String(bytes).trim());
break;
default:
data.readFully(bytes);
break;
}
}
return info;
}
catch (EOFException e) {
System.err.println(e.toString());
}
return null;
}
public boolean convert(SyncObject object, DataBuffer buffer, int version) {
if (version == getSyncVersion()) {
if (object instanceof RestaurantInfo )
{
String name = ((RestaurantInfo)object).getElement(
RestaurantInfo.NAME);
String phone = ((RestaurantInfo)object).getElement(
RestaurantInfo.PHONE);
String address = ((RestaurantInfo)object).getElement(
RestaurantInfo.ADDRESS);
String specialty = ((RestaurantInfo)object).getElement(
RestaurantInfo.SPECIALTY);
buffer.writeShort(name.length()+1);
buffer.writeByte(FIELDTAG_NAME);
buffer.write(name.getBytes());
buffer.writeByte(0);
buffer.writeShort(phone.length()+1);
buffer.writeByte(FIELDTAG_PHONE);
buffer.write(phone.getBytes());
buffer.writeByte(0);
buffer.writeShort(address.length()+1);
buffer.writeByte(FIELDTAG_ADDRESS);
buffer.write(address.getBytes());
buffer.writeByte(0);
buffer.writeShort(specialty.length()+1);
buffer.writeByte(FIELDTAG_SPECIALTY);
buffer.write(specialty.getBytes());
buffer.writeByte(0);
return true;
}
}
return false;
}
public void beginTransaction() {
store = PersistentStore.getPersistentObject(KEY);
_data = (Vector)store.getContents();
}
public void endTransaction() {
store.setContents(_data);
store.commit();
}
public SyncConverter getSyncConverter() {
return this;
}
public String getSyncName() {
return "Restaurant Synchronization Demo";
}
public String getSyncName(Locale locale) {
return getSyncName();
}
public int getSyncObjectCount() {
store = PersistentStore.getPersistentObject(KEY);
_data = (Vector)store.getContents();
return _data.size();
}
public SyncObject[] getSyncObjects() {
SyncObject[] array = new SyncObject[_data.size()];
for (int i = _data.size() - 1; i >= 0; --i) {
array[i] = (SyncObject)_data.elementAt(i);
}
return array;
}
public SyncObject getSyncObject(int uid) {
for (int i = _data.size() -1; i>= 0; --i) {
SyncObject so = (SyncObject)_data.elementAt(i);
if (so.getUID() == uid ) return so;
}
return null;
}
public int getSyncVersion() {
return 1;
}
public boolean addSyncObject(SyncObject object) {
_data.addElement(object);
return true;
}
public boolean removeAllSyncObjects() {
_data.removeAllElements();
return true;
}
public void clearSyncObjectDirty(SyncObject object) {
// Not applicable.
}
public boolean isSyncObjectDirty(SyncObject object) {
return false;
}
public boolean removeSyncObject(SyncObject object) {
return false;
}
public void setSyncObjectDirty(SyncObject object) {
}
public boolean updateSyncObject(SyncObject oldObject, SyncObject newObject) {
return false;
}
public RestaurantsSync() {
MainScreen mainScreen = new MainScreen();
mainScreen.setTitle(new LabelField( _resources.getString(APPLICATION_TITLE)));
namefield = new AutoTextEditField(_resources.getString(FIELD_NAME), "");
addressfield = new AutoTextEditField( _resources.getString(FIELD_ADDRESS),"");
phonefield = new EditField( _resources.getString(FIELD_PHONE), "",
Integer.MAX_VALUE, BasicEditField.FILTER_PHONE);
specialtyfield = new EditField(_resources.getString(FIELD_SPECIALTY), "",
Integer.MAX_VALUE, BasicEditField.FILTER_DEFAULT);
mainScreen.add(namefield);
mainScreen.add(addressfield);
mainScreen.add(phonefield);
mainScreen.add(specialtyfield);
mainScreen.addKeyListener(this);
mainScreen.addTrackwheelListener(this);
pushScreen(mainScreen);
}
public void makeMenu( Menu menu, int instance) {
menu.add(saveItem);
menu.add(getItem);
super.makeMenu(menu, instance);
}
public void onExit() {
Dialog.alert(_resources.getString(APP_EXIT));
}
Last Updated:2007年2月2日