十一月's profileNOVEMBREBlogListsGuestbookMore ![]() | Help |
|
|
February 22 NOKIA暗码大全暗 码 用 途 备 注 *#06# 查询IMEI号码 所有手机通用 *#7370# 格式化手机 Series 60手机专用 *#7780# 恢复出厂设置 Series 60和Series 40手机通用 *#0000# 查询当前软件版本号 所有手机通用 *#7760# 查询生产线号码 Series 40手机专用 *#2820# 查询蓝牙设备地址 Series 60和Series 40手机通用 *3370# 激活EFR 部分型号的手机可用 #3370# 关闭EFR 部分型号的手机可用 *4720# 激活HFR 部分型号的手机可用 #4720# 关闭HFR 部分型号的手机可用 *#92702689# 查询总通话时间 仅限6630 *#92702689# 进入数据模式 Series 40手机专用 *#7370925538# 为手机上锁 Series 60手机专用 一、*#06#:显示IMEI码 二、*#0000#:显示软件版本 (部分型号如果不起作用,可按*#型号代码#,如*#6110#) 第一行--软件版本; 第二行--软件发布日期; 第三行--手机型号 三、*#92702689#:显示序列号和IMEI码,带滚动菜单 第一屏表示 - 手机出厂时间:1197(月月年年); 第二屏表示 - 串号和IMEI; 第三屏表示 - 购买时间:1197(月月年年)可以更改一次 (但一经输入就不能再作更改,日期会被永久记录) 第四屏表示 - 最后修理时间:0000(月月年年)维修时设置。 第五屏表示 - 传输用户数据:退出关闭电话,然后返回。 如果以上工作不正常,并且电话要求您输入一个合法的代码,可试试: 1).6232(OK):显示制造的月和年 2).7832(OK):显示手机购买时间的月和年 3).7332(OK):显示最近维修时间的月和年:0000(月月年年)维修时设置 4).9268(OK):显示系列号 5).37832(OK):设置购买时间的月和年(警告:只允许做一次) 6).87267(OK):确认传输,与软件更新有关 四、速率编码 *3370#或*efr#:开启(EFR)全速率编码 #3370#或#efr#:关闭全速率编码 (开启全速增强型编码模式,可改善话音质量但会耗电) *4720#或*hra0#:开启(HR)半速率编码 #4720#或#hra0#:关闭半速率编码 (话音质量降低,但可延长电池大概30%左右使用时间,需网络支持) 键入这些代码后,会关机重开,然后才能生效。 五、SIM卡锁信息 *#746025625# (= *#sim0clock#):如果SIM卡能被锁,进行检测时键入该指令后,手机显示\"SIM CLOCK STOP ALLOWED\" or \"SIM CLOCK STOP NOT ALLOWED\",这取决于你的SIM卡。 SIM卡锁信息:包括四种不同的锁 1).国家锁--锁指定的国家 2).网络锁--锁指定的网络 3).供应商锁--锁服务提供商 4).SIM卡锁--锁指定的SIM卡 六、查询手机是否锁频 首先必须找出设定手机时必须使用的几个键。其中,连续按*键二次即出现\"+\";连续按*键三次即出现\"p\";连续按*键四次即出现\"w\"。然后,你就可以依次顺序输入相应组合键。 #pw+1234567890+1#:查询是否锁国家码 #pw+1234567890+2#:查询是否锁网络码 #pw+1234567890+3#:查询是否锁网络提供者锁定的码 #pw+1234567890+4#:查询是否锁SIM卡 优秀的J2ME网站集锦http://java.sun.com/javame/
一些实用的图形用户界面方法
这个函数已反复应用于多个手机应用软件平台 用法:参数定义:str——要分割的字符串 半透明技术(限MIDP2.0) // 获得半透明图片,透明度从0到10共分为11个等级 灰度图转化函数// 得到灰度图
图片透明效果
常见属性(Property)及其作用列表在J2ME开发中,我们经常需要和手机系统进行交互,获得一些和系统相关的信息,在J2ME API设计中,提供了一系列的系统属性,可以让我们来进行获得,下面就一一进行介绍。
表1 CLDC、MIDP和JTWI属性
表2 可选包属性
表3 MMAPI属性
表4 Wireless Messaging API属性
表5 FileConnection API
使用这些属性,可以获得在程序运行过程中需要的很多和系统相关的信息,也可以使用表2中的属性来获得手机是否支持对应的可选包等信息。
实际使用示例:
String name = System.getProperty(“microedition.platform”);
注意:如果需要获得JVM或jad文件中的信息,需要使用MIDlet类中的getAppProperty方法,其属性名则需要查阅jad文件的设定,和本文所述的属性名无关。
February 21 数据库和 MIDP,第 5 部分:搜索记录存储在本系列文章的第四部分中,您学会如何遍历一个记录存储,按照有用的次序排序记录,以及使用过滤器选择期望的记录。本文探索各种用于发现符合指定准则的一个或多个记录的策略。 搜索策略很明显,搜索一个特定记录或者记录集合的最简单方式是使用过滤器。该过滤器需要知道数据是如何存储在一个记录中的,因此您将希望在任何可能的情况下重用您的数据映射类。例如,在第 3 部分中我们定义
现在,我们扩展
假设我们这样定义一个如下的
一个匹配特定姓氏的过滤器看起来类似于:
发现匹配的记录是一件简单的事情:
仔细地编码,您可以避免打开任何不需要的记录。您可以采取的一个方法是在内存中缓存最近访问的记录。例如,每当过滤器匹配一个记录时,打开该记录并且将它的已打开形式存储到缓存中,这种打开形式通常是一个表示单一实体的对象,例如雇员。将它的记录 ID 用作关键字 —— 当然,您需要在记录中存储 ID。当您遍历该枚举时,在访问底层记录存储之前检查已打开记录的缓存。 实际上,使用枚举方式将匹配记录收集和打开为单独的列表可能更为简单。考虑我们在第 2 部分中定义的 Contact 类,它的简单的
下面的类使用记录过滤器作为一种发现和存储匹配记录的方式。它返回
不幸的是,内存限制可能阻止每次缓存更多的对象。您可以通过使用索引搜索一张单独维护的表,从而获得某些性能。这个表将记录 ID 与关键字值例如联系名相配对。一个索引通常足够的小,以便于将它保持在内存中,并且省去您每次需要发现特定记录时都要使用枚举的麻烦。 关于作者Eric Giguere 是 iAnywhere Solutions 的一名软件开发人员,iAnywhere Solutions 是 Sybase 的一个子公司,他在那里从事关于手持设备和无线计算的 Java 技术。他拥有 Waterloo 大学计算机科学的学士和硕士学位,并广泛撰写有关计算主题的文章。 数据库和 MIDP,第 4 部分:过滤和遍历策略在本系列文章的第 2 和第 3 部分,我们讨论在数据和字节数组之间相互映射的基本方式,从而在记录存储中存储它们,这些记录存储是通过记录管理系统(Record Management System,RMS)管理的。读写数据总是需要克服的第一个障碍,但是发现您所需要的数据也同样的重要,并且这样做的话,您需要能够浏览记录存储,以一种有用的方式排序记录,以及使用过滤器提取出想要的数据。本文探索执行这些任务的不同策略;第 5 部分将建立在这里所学知识的基础之上,并且向您展示如何搜索满足指定规则的记录。 记录 ID 并不是索引为了读或写一条记录,您需要知道它的记录 ID。在第 1 部分中,您了解到记录 ID 是一个整数值,它唯一地标识在记录存储中的一条记录 - 并且它不是记录存储中的索引。这个差异具有某些重要的含义。 如果具有 N 个记录的存储被索引,那么每条记录都将具有一个索引,其范围是 0 到 N-1 或者 1 到 N,这取决于范围是从 0 还是从 1 开始的。每当一条记录被删除或者插入的时候,在存储中的位于后面的记录索引将会相应的改变。该范围将会收缩或者增长,但是保持连续。 与索引不同的是,在记录存储中,无论在一条记录之前插入或者去除多少个其他的记录,该记录 ID 并不改变。增加到记录存储中的第一条记录将其记录 ID 赋值为 1,下一条记录 ID 为 2,等等。如果您删除一条记录,它的记录 ID 变为无效,并且任何访问该记录的企图都会抛出 由于它们唯一地标识记录,因此您可以通过将一个记录的 ID 存储为另一条记录中的数据值,从而使用记录 ID 将两个或者更多记录连接到一起。您还可以使用记录 ID 来同步数据和外部应用程序,正如您将在第 6 部分中所看到的。 记录 ID 的主要缺点是它们使记录存储遍历变得复杂化;您不能像在数组中那样,在一个索引集合中进行迭代。您必须使用两种遍历技术之一:强制或者枚举。 强制遍历利用强制方法,您只是简单地逐个提取记录,从第一条记录开始,忽略无效的记录,一直继续直到您已经获取所有的记录:
该代码调用 强制方法易于理解,并且如果缺失记录很少的话,将会工作得很好,但是首选的方法是使用枚举。 枚举记录并不是检查每个记录 ID 以查看哪个记录是有效的,这本质上是强制方法所做的,您可以使用 您可以针对希望遍历的记录存储调用 enume
出于简单性考虑,异常处理已经从该代码片断中被忽略了,但是应该意识到
当您已经处理完一个枚举,您必须调用它的 使用
您还可以使用 一个未排序枚举返回其记录的顺序是特定于实现,因此不要基于该顺序做出任何假设。 出于方便性考虑,您可以使用
然而,您将不会知道正在讨论的记录 ID,或者不能直接将数据读取到您已经分配的字节数组中。然而,如果您正在过滤或者排序枚举,数据可能被缓存在内存中,因此从枚举中获取它可能比从底层的记录存储获取更为有效。 一个对于 使用 使用 过滤枚举记录只是对于在记录存储中的数据子集感兴趣吗?您可以通过使用一个过滤器,从而具有一个忽略不必要记录的枚举,该过滤器实现
理想情况是,您需要过滤的信息是在数组的开头 —— 您希望尽可能快地确定一个匹配。为了使用一个过滤器,将它作为第一个参数传递给
记录 ID 并不传递给过滤器,只有字节数组包括记录数据。如果您必须知道正被匹配的是哪个记录 ID,您将需要在该记录中存储它自己的 ID,或者使用某些其他的方式从记录的数据中标识该记录。 例如,在第 3 部分中我们使用记录存储中的第一条记录,用于保持其余记录中的域的有关信息 —— 很明显,您希望将该记录从任何枚举中过滤出去。 排序枚举记录为了保证记录以一种一致的、可预测的次序被返回,您必须排序该枚举。您向该枚举提供一个比较器,这是一个实现
注意常量
利用过滤器,没有记录标识符会被传递给比较器,只是原始的记录数据。 当您创建枚举时,可以提供过滤器和比较器。如果您这样做的话,在数据被排序之前应用过滤器。 下一步工作现在,我们知道如何移动记录存储,以及如何排序和过滤记录,您已经准备好学习第 5 部分,该部分将描述相关策略,用于搜索一条记录存储中符合特定准则的对象。 关于作者Eric Giguere 是 iAnywhere Solutions 的一名软件开发人员,iAnywhere Solutions 是 Sybase 的一个子公司,他在那里从事关于手持设备和无线计算的 Java 技术。他拥有 Waterloo 大学计算机科学的学士和硕士学位,并广泛撰写有关计算主题的文章。 数据库和 MIDP,第三部分:使用数据映射
本系列中的 第二部分 介绍了数据映射的基本知识。您学会了如何在字节数组(byte array)中存储原始数据类型的数值,如何使用流向记录库(record store)中存储对象和从记录库中检索对象以及如何从字节数组中抽取已存储的数值。在本文中,您将学会如何使您的应用程序远离这些低级操作,方法是对核心类进行扩展使其包含读写操作,创建并使用字段列表来存储和检索对象。 扩展核心类J2ME 开发人员的目标之一是最小化应用程序对内存的使用。理想情况下,在任何给定的时间内,内存中应该只含有某个数据块的一个副本。然而,当您向 package j2me.io;
import java.io.*;
// A version of ByteArrayOutputStream that gives you
// direct access to the underlying byte array if
// you need it.
public class DirectByteArrayOutputStream
extends ByteArrayOutputStream {
// Constructs a byte array output stream of default size
public DirectByteArrayOutputStream(){
super();
}
// Constructs a byte array output stream of given size
public DirectByteArrayOutputStream( int size ){
super( size );
}
// Returns a reference to the underlying byte array.
// The actual amount of data in the byte array is
// obtained via the size method.
public synchronized byte[] getByteArray(){
return buf;
}
// Swaps in a new byte array for the old one, resetting
// the count as well.
public synchronized byte[] swap( byte[] newBuf ){
byte[] oldBuf = buf;
buf = newBuf;
reset();
return oldBuf;
}
}
记住调用 ... DirectByteArrayOutputStream bout = ... RecordStore rs = ... int numBytes = bout.size(); byte[] data = bout.getByteArray(); rs.addRecord( data, 0, numBytes ); ... 未来保持一致性,您可以用类似的方法对 package j2me.io;
import java.io.*;
// A version of ByteArrayInputStream that lets you
// replace the underlying byte array.
public class DirectByteArrayInputStream
extends ByteArrayInputStream {
// Constructs an output stream from the given array
public DirectByteArrayInputStream( byte buf[] ){
super( buf );
}
// Constructs an output stream from the given subarray
public DirectByteArrayInputStream( byte buf[],
int offset,
int length ){
super( buf, offset, length );
}
// Resets the array the stream reads from
public synchronized void setByteArray( byte[] buf ){
this.buf = buf;
this.pos = 0;
this.count = buf.length;
this.mark = 0;
}
// Resets the array the stream reads from
public synchronized void setByteArray( byte[] buf,
int offset,
int length ){
this.buf = buf;
this.pos = offset;
this.count = Math.min( offset + length, buf.length );
this.mark = offset;
}
}
注意类 您也可以很容易的对 package j2me.io;
import java.io.*;
public class ExtendedDataOutputStream extends DataOutputStream {
public ExtendedDataOutputStream( OutputStream out ){
super( out );
}
public final void writeIntArray( int[] arr )
throws IOException {
int size = arr.length;
writeInt( size );
for( int i = 0; i < size; ++i ){
writeInt( arr[i] );
}
}
}
相反,您可以将这种代码放入一个帮助器类,因为您不需要访问任何的 protected members。 创建记录字段现在您已经拥有了创建基于字段的记录库的所有工具,记录库中的每条记录都是一组指定类型的命名字段。您利用两个类来管理该记录库。其中的第一个类 package j2me.rms;
import java.io.*;
import javax.microedition.rms.*;
// Maintains information about the fields in a
// field-based record store. Currently just a list of
// field types and (optional) field names, but could
// easily be expanded to store other information.
public class FieldList {
private static final int VERSION = 1;
// The basic field types.
public static final byte TYPE_BOOLEAN = 1;
public static final byte TYPE_BYTE = 2;
public static final byte TYPE_CHAR = 3;
public static final byte TYPE_SHORT = 4;
public static final byte TYPE_INT = 5;
public static final byte TYPE_LONG = 6;
public static final byte TYPE_STRING = 7;
// Constructs an empty list.
public FieldList(){
}
// Constructs a list of the given size.
public FieldList( int numFields ){
if( numFields < 0 || numFields > 255 ){
throw new IllegalArgumentException(
"Bad number of fields" );
}
_types = new byte[ numFields ];
_names = new String[ numFields ];
}
// Returns the number of fields.
public int getFieldCount(){
return _types != null ? _types.length : 0;
}
// Returns the name of a field.
public String getFieldName( int index ){
String name = _names[ index ];
return name != null ? name : "";
}
// Returns the type of a field.
public byte getFieldType( int index ){
return _types[ index ];
}
// Reads the field list from a byte array.
public void fromByteArray( byte[] data )
throws IOException {
ByteArrayInputStream bin =
new ByteArrayInputStream( data );
fromDataStream( new DataInputStream( bin ) );
bin.close();
}
// Reads the fields list from a data stream.
public void fromDataStream( DataInputStream din )
throws IOException {
int version = din.readUnsignedByte();
if( version != VERSION ){
throw new IOException( "Incorrect version " +
version + " for FieldList, expected " +
VERSION );
}
int numFields = din.readUnsignedByte();
_types = new byte[ numFields ];
_names = new String[ numFields ];
if( numFields > 0 ){
din.readFully( _types );
for( int i = 0; i < numFields; ++i ){
_names[i] = din.readUTF();
}
}
}
// Reads a field list from a record store.
public void fromRecordStore( RecordStore rs, int index )
throws IOException,
RecordStoreException {
fromByteArray( rs.getRecord( index ) );
}
// Sets the name of a field.
public void setFieldName( int index, String name ){
_names[ index ] = name;
}
// Sets the type of a field.
public void setFieldType( int index, byte type ){
_types[ index ] = type;
}
// Stores the fields list to a byte array
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream bout =
new ByteArrayOutputStream();
toDataStream( new DataOutputStream( bout ) );
byte[] data = bout.toByteArray();
bout.close();
return data;
}
// Stores the fields list to a data stream
public void toDataStream( DataOutputStream out )
throws IOException {
out.writeByte( VERSION );
int count = getFieldCount();
out.writeByte( count );
if( count > 0 ){
out.write( _types, 0, count );
for( int i = 0; i < count; ++i ){
out.writeUTF( getFieldName( i ) );
}
}
}
// Writes a field list to a record store.
public int toRecordStore( RecordStore rs, int index )
throws IOException,
RecordStoreException {
byte[] data = toByteArray();
boolean add = true;
if( index > 0 ){
try {
rs.setRecord( index, data, 0, data.length );
add = false;
}
catch( InvalidRecordIDException e ){
}
}
// If the record doesn't actually exist yet,
// go ahead and create it by inserting dummy
// records ahead of it
if( add ){
synchronized( rs ){
int nextID = rs.getNextRecordID();
if( index <= 0 ) index = nextID;
while( nextID < index ){
rs.addRecord( null, 0, 0 );
}
if( nextID == index ){
rs.addRecord( data, 0, data.length );
}
}
}
return index;
}
private String[] _names;
private byte[] _types;
}
实际上,一个 在其核心,一个 ... FieldList depts = new FieldList( 3 ); depts.setFieldType( 0, FieldList.TYPE_SHORT ); depts.setFieldName( 0, "ID" ); depts.setFieldType( 1, FieldList.TYPE_STRING ); depts.setFieldName( 1, "Name" ); depts.setFieldType( 2, FieldList.TYPE_INT ); depts.setFieldName( 2, "ManagerID" ); ... 一个 实例可存储在一个数据流、一个字节数组或者一个记录库中。如果您将字段列表存储为记录库中的第一条记录,则任何可打开该记录库的代码就可以读取该记录以决定其余字段的字段布局。要使这个策略起到作用,您必须在创建记录库后立即存储记录列表: ...
FieldList list = ... // a field list
RecordStore rs = RecordStore.openRecordStore( "foo", true );
if( rs.getNumRecords() == 0 ){ // empty, store it
list.toRecordStore( rs, -1 );
}
...
管理基于字段的记录库所需的第二个类是 package j2me.rms;
import java.io.*;
import javax.microedition.rms.*;
import j2me.io.*;
// A wrapper class for a record store that allows the
// records to be accessed as a set of fields. The field
// definitions are maintained separately using a FieldList
// object, which can be stored as part of the record store
// or separately.
public class FieldBasedStore {
// Some useful constants
public static Boolean TRUE = new Boolean( true );
public static Boolean FALSE = new Boolean( false );
// Markers for the types of string we support
private static final byte NULL_STRING_MARKER = 0;
private static final byte UTF_STRING_MARKER = 1;
// Constructs a field store where the field list is
// assumed to be stored in the first record.
public FieldBasedStore( RecordStore rs )
throws IOException,
RecordStoreException {
this( rs, 1 );
}
// Constructs a field store where the field list is
// stored in the given record.
public FieldBasedStore( RecordStore rs, int fieldListID )
throws IOException,
RecordStoreException {
this( rs, loadFieldList( rs, fieldListID ) );
}
// Constructs a field store with the given field list.
public FieldBasedStore( RecordStore rs, FieldList list ){
_rs = rs;
_fieldList = list;
}
// Adds a new record to the store. Returns the new
// record ID.
public synchronized int addRecord( Object[] fields )
throws IOException,
RecordStoreException {
writeStream( fields );
byte[] data = _bout.getByteArray();
return _rs.addRecord( data, 0, data.length );
}
// Returns the current field list.
public FieldList getFieldList(){
return _fieldList;
}
// Returns the record store.
public RecordStore getRecordStore(){
return _rs;
}
// Loads the field list from the record store.
private static FieldList loadFieldList( RecordStore rs,
int fieldListID )
throws IOException,
RecordStoreException {
FieldList list = new FieldList();
list.fromRecordStore( rs, fieldListID );
return list;
}
// Prepares the store for input by making sure that
// the data buffer is big enough. The streams are
// reused.
private void prepareForInput( int size ){
if( _buffer == null || _buffer.length < size ){
_buffer = new byte[ size ];
}
if( _bin == null ){
_bin = new DirectByteArrayInputStream( _buffer );
_din = new DataInputStream( _bin );
} else {
_bin.setByteArray( _buffer );
}
}
// Prepares the store for output. The streams are reused.
private void prepareForOutput(){
if( _bout == null ){
_bout = new DirectByteArrayOutputStream();
_dout = new DataOutputStream( _bout );
} else {
_bout.reset();
}
}
// Reads a field from the buffer.
private Object readField( int type ) throws IOException {
switch( type ){
case FieldList.TYPE_BOOLEAN:
return _din.readBoolean() ? TRUE : FALSE;
case FieldList.TYPE_BYTE:
return new Byte( _din.readByte() );
case FieldList.TYPE_CHAR:
return new Character( _din.readChar() );
case FieldList.TYPE_SHORT:
return new Short( _din.readShort() );
case FieldList.TYPE_INT:
return new Integer( _din.readInt() );
case FieldList.TYPE_LONG:
return new Long( _din.readLong() );
case FieldList.TYPE_STRING: {
byte marker = _din.readByte();
if( marker == UTF_STRING_MARKER ){
return _din.readUTF();
}
}
}
return null;
}
// Reads the record at the given ID and returns it as
// a set of objects that match the types in the
// field list.
public synchronized Object[] readRecord( int recordID )
throws IOException,
RecordStoreException {
prepareForInput( _rs.getRecordSize( recordID ) );
_rs.getRecord( recordID, _buffer, 0 );
int count = _fieldList.getFieldCount();
Object[] fields = new Object[ count ];
for( int i = 0; i < count; ++i ){
fields[i] = readField(_fieldList.getFieldType(i));
}
return fields;
}
// Converts an object to a boolean value.
public static boolean toBoolean( Object value ){
if( value instanceof Boolean ){
return ((Boolean) value).booleanValue();
} else if( value != null ){
String str = value.toString().trim();
if( str.equals( "true" ) ) return true;
if( str.equals( "false" ) ) return false;
return( toInt( value ) != 0 );
}
return false;
}
// Converts an object to a char.
public static char toChar( Object value ){
if( value instanceof Character ){
return ((Character) value).charValue();
} else if( value != null ){
String s = value.toString();
if( s.length() > 0 ){
return s.charAt( 0 );
}
}
return 0;
}
// Converts an object to an int. This code
// would be much simpler if the CLDC supported
// the java.lang.Number class.
public static int toInt( Object value ){
if( value instanceof Integer ){
return ((Integer) value).intValue();
} else if( value instanceof Boolean ){
return ((Boolean) value).booleanValue() ? 1 : 0;
} else if( value instanceof Byte ){
return ((Byte) value).byteValue();
} else if( value instanceof Character ){
return ((Character) value).charValue();
} else if( value instanceof Short ){
return ((Short) value).shortValue();
} else if( value instanceof Long ){
return (int) ((Long) value).longValue();
} else if( value != null ){
try {
return Integer.parseInt( value.toString() );
}
catch( NumberFormatException e ){
}
}
return 0;
}
// Converts an object to a long. This code
// would be much simpler if the CLDC supported
// the java.lang.Number class.
public static long toLong( Object value ){
if( value instanceof Integer ){
return ((Integer) value).longValue();
} else if( value instanceof Boolean ){
return ((Boolean) value).booleanValue() ? 1 : 0;
} else if( value instanceof Byte ){
return ((Byte) value).byteValue();
} else if( value instanceof Character ){
return ((Character) value).charValue();
} else if( value instanceof Short ){
return ((Short) value).shortValue();
} else if( value instanceof Long ){
return ((Long) value).longValue();
} else if( value != null ){
try {
return Long.parseLong( value.toString() );
}
catch( NumberFormatException e ){
}
}
return 0;
}
// Writes a field to the output buffer.
private void writeField( int type, Object value )
throws IOException {
switch( type ){
case FieldList.TYPE_BOOLEAN:
_dout.writeBoolean( toBoolean( value ) );
break;
case FieldList.TYPE_BYTE:
_dout.write( (byte) toInt( value ) );
break;
case FieldList.TYPE_CHAR:
_dout.writeChar( toChar( value ) );
break;
case FieldList.TYPE_SHORT:
_dout.writeShort( (short) toInt( value ) );
break;
case FieldList.TYPE_INT:
_dout.writeInt( toInt( value ) );
break;
case FieldList.TYPE_LONG:
_dout.writeLong( toLong( value ) );
break;
case FieldList.TYPE_STRING:
if( value != null ){
String str = value.toString();
_dout.writeByte( UTF_STRING_MARKER );
_dout.writeUTF( str );
} else {
_dout.writeByte( NULL_STRING_MARKER );
}
break;
}
}
// Writes a set of fields to the given record. The
// fields must be compatible with the types in
// the field list.
public synchronized void writeRecord( int recordID,
Object[] fields )
throws IOException,
RecordStoreException {
writeStream( fields );
byte[] data = _bout.getByteArray();
_rs.setRecord( recordID, data, 0, data.length );
}
// Writes a set of fields to the output stream.
private void writeStream( Object[] fields )
throws IOException {
int count = _fieldList.getFieldCount();
int len = ( fields != null ? fields.length : 0 );
prepareForOutput();
for( int i = 0; i < count; ++i ){
writeField( _fieldList.getFieldType( i ),
( i < len ? fields[i] : null ) );
}
}
private DirectByteArrayInputStream _bin;
private DirectByteArrayOutputStream _bout;
private byte[] _buffer;
private DataInputStream _din;
private DataOutputStream _dout;
private FieldList _fieldList;
private RecordStore _rs;
}
要创建一个 ... RecordStore rs = ... // an open record store FieldBasedStore fstore = new FieldBasedStore( rs ); ... 或者您可以对其进行显式指定: ... RecordStore rs = ... // an open record store FieldList list = ... // a field list FieldBasedStore fstore = new FieldBasedStore( rs, list ); ...
...
Object[] fields = new Object[]{
new Short( 1 ), "Accounting", new Integer( 100 )
};
int recordID = fstore.addRecord( fields );
...
注意 ...
Object[] fields = new Object[]{ "1", "Accounting", "100" };
int recordID = fstore.addRecord( fields );
...
读取记录也同样简单: ...
Object[] fields = fstore.readRecord( recordID );
for( int i = 0; i < fields.length; ++i ){
System.out.println( "Field: " +
fstore.getFieldList().getFieldName( i ) +
" Value: " + fields[i] );
}
...
您可以在任何时候重写该数组来修改记录: ... Object[] fields = fstore.readRecord( recordID ); fields[2] = "134"; // change the manager fstore.writeRecord( recordID, fields ); ... 这里有一个 MIDlet 的示例,它使用了一对基于字段的记录库来存储和检索雇员和部门数据。它也可使用 第一部分 所述的 import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
import javax.microedition.rms.*;
import j2me.rms.*;
// A simple MIDlet for testing RMS mappings
// done using the FieldBasedStore class.
public class RMSMappings extends MIDlet
implements CommandListener {
private Display display;
public static final Command exitCommand =
new Command( "Exit",
Command.EXIT, 1 );
public static final Command testCommand =
new Command( "Test",
Command.SCREEN, 1 );
private static Object[][] empList = {
new Object[]{ "1", "Mary", "CEO", "100", "F" },
new Object[]{ "2", "John", "CFO", "200", "M" },
new Object[]{ "3", "Pat", "Closem", "300", "F" },
new Object[]{ "4", "PJ", "Admin", "100", "M" },
};
private static Object[][] deptList = {
new Object[]{ "100", "Executive", "1" },
new Object[]{ "200", "Operations", "2" },
new Object[]{ "300", "Sales", "1" },
};
public RMSMappings(){
}
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
} else if( c == testCommand ){
runTest();
}
}
protected void destroyApp( boolean unconditional )
throws MIDletStateChangeException {
exitMIDlet();
}
public void exitMIDlet(){
notifyDestroyed();
}
public Display getDisplay(){ return display; }
protected void initMIDlet(){
display.setCurrent( new MainForm() );
}
protected void pauseApp(){
}
private void printRecord( FieldBasedStore store,
int recordID ){
try {
FieldList list = store.getFieldList();
Object[] fields = store.readRecord( recordID );
if( fields.length != list.getFieldCount() ){
System.out.println( "Error: bad count" );
return;
}
System.out.println( "Record " + recordID + ":" );
for( int i = 0; i < fields.length; ++i ){
System.out.println( " " +
list.getFieldName( i ) + ": " +
fields[i] );
}
}
catch( RecordStoreException e ){
}
catch( IOException e ){
}
}
private void runTest(){
// First delete the record stores...
System.out.println( "Deleting record stores..." );
String[] names = RecordStore.listRecordStores();
for( int i = 0; i < names.length; ++i ){
try {
RecordStore.deleteRecordStore( names[i] );
} catch( RecordStoreException e ){
System.out.println( "Could not delete " +
names[i] );
}
}
// Create two record stores, one with a field list
// stored in the first record and the second with
// a field list stored separately (in the app)
RecordStore empRS = null;
RecordStore deptRS = null;
FieldList empFields = new FieldList( 5 );
FieldList deptFields = new FieldList( 3 );
FieldBasedStore employees;
FieldBasedStore departments;
empFields.setFieldType( 0, FieldList.TYPE_INT );
empFields.setFieldName( 0, "ID" );
empFields.setFieldType( 1, FieldList.TYPE_STRING );
empFields.setFieldName( 1, "Given Name" );
empFields.setFieldType( 2, FieldList.TYPE_STRING );
empFields.setFieldName( 2, "Last Name" );
empFields.setFieldType( 3, FieldList.TYPE_BOOLEAN );
empFields.setFieldName( 3, "Active" );
empFields.setFieldType( 4, FieldList.TYPE_CHAR );
empFields.setFieldName( 4, "Sex" );
System.out.println( "Initializing employees" );
try {
empRS = RecordStore.openRecordStore( "empRS",
true );
// now store the field list in the RS
empFields.toRecordStore( empRS, -1 );
employees = new FieldBasedStore( empRS );
}
catch( RecordStoreException e ){
System.out.println( "Could not create empRS" );
return;
}
catch( IOException e ){
System.out.println( "Error storing field list" );
return;
}
System.out.println( "Initializing departments" );
deptFields.setFieldType( 0, FieldList.TYPE_INT );
deptFields.setFieldName( 0, "ID" );
deptFields.setFieldType( 1, FieldList.TYPE_STRING );
deptFields.setFieldName( 1, "Name" );
deptFields.setFieldType( 2, FieldList.TYPE_INT );
deptFields.setFieldName( 2, "Manager" );
try {
deptRS = RecordStore.openRecordStore( "deptRS",
true );
departments = new FieldBasedStore( deptRS,
deptFields );
}
catch( RecordStoreException e ){
System.out.println( "Could not create deptRS" );
return;
}
int[] empRecordID;
int[] deptRecordID;
int i;
// Add the data...
try {
empRecordID = new int[ empList.length ];
for( i = 0; i < empList.length; ++i ){
empRecordID[i] =
employees.addRecord( empList[i] );
}
deptRecordID = new int[ deptList.length ];
for( i = 0; i < deptList.length; ++i ){
deptRecordID[i] =
departments.addRecord( deptList[i] );
}
}
catch( RecordStoreException e ){
System.out.println( "Error adding record" );
return;
}
catch( IOException e ){
System.out.println( "Error writing field" );
return;
}
// Now fetch the data back and print it...
System.out.println( "---- Employee data ----" );
for( i = 0; i < empRecordID.length; ++i ){
printRecord( employees, empRecordID[i] );
}
System.out.println( "---- Department data ----" );
for( i = 0; i < deptRecordID.length; ++i ){
printRecord( departments, deptRecordID[i] );
}
System.out.println( "Closing empRS" );
try {
empRS.closeRecordStore();
}
catch( RecordStoreException e ){
System.out.println( "Error closing empRS" );
}
System.out.println( "Closing deptRS" );
try {
deptRS.closeRecordStore();
}
catch( RecordStoreException e ){
System.out.println( "Error closing deptRS" );
}
System.out.println( "Dumping record stores..." );
// Analyze them...
RMSAnalyzer analyzer = new RMSAnalyzer(
new RMSAnalyzer.SystemLogger( 10 ) );
analyzer.analyzeAll();
}
protected void startApp()
throws MIDletStateChangeException {
if( display == null ){
display = Display.getDisplay( this );
initMIDlet();
}
}
public class MainForm extends Form {
public MainForm(){
super( "RMSMappings" );
addCommand( exitCommand );
addCommand( testCommand );
setCommandListener( RMSMappings.this );
}
}
}
正如它们现在所表明的,
下一部分提要第四节将讨论使用 RMS 的更高级的方面:遍历记录库和筛选记录。 关于作者Eric Giguere 是来自 Sybase 子公司 iAnywhere Solutions 的一个软件开发人员,主要从事用于手持设备和无线计算的 Java 技术。他拥有 Waterloo 大学的 BMath 和 MMath 学位,并广泛撰写有关计算主题的文章。 数据库和 MIDP,第二部分:数据映射数据库和 MIDP,第二部分:数据映射 作者:Eric Giguere 正如 第一部分 所述,移动信息设备描述 (Mobile Information Device Profile,MIDP) 通过记录管理系统 (Record Management System,RMS) 提供数据持久存储。MIDP 对持久存储的支持局限于简单的字节数组 (byte array),且记录的读写是按整体进行,而不是按字段进行的。因此,RMS 应用程序编程接口 (API) 非常简单,但它要求应用程序使用一个非常简单的二进制格式进行数据存储。 本文将描述封装低级存储操作的数据映射策略,目的是提高应用程序存储和检索持久数据的效率。 数据操作的核心类实际上,将数据写到一个记录库 (record store) 和通过网络向服务器发送数据包并没有什么区别。MIDP 基于其上的有限连接设备配置 (Connected Limited Device Configuration,CLDC) 包括源自 J2SE 核心库的标准数据操作类,这些类对于 RMS 操作十分有用。使用通用接口的一个很大的好处是,MIDlet 可以更容易地和运行在标准和企业 Java 平台上的应用程序进行互操作。 字节数组流
...
byte[] data = new byte[]{ 1, 2, 3 };
ByteArrayInputStream bin = new ByteArrayInputStream( data );
int b;
while( ( b = bin.read() ) != -1 ){
System.out.println( b );
}
try {
bin.close();
} catch( IOException e ){
// never thrown in this case
}
...
输入流将顺序返回该数组中的每个字节,直到数组的尾部。利用 对象 ...
ByteArrayOutputStream bout = new ByteArrayOutputStream();
bout.write( 1 );
bout.write( 2 );
bout.write( 3 );
byte[] data = bout.toByteArray();
for( int i = 0; i < data.length; ++i ){
System.out.println( data[i] );
}
try {
bout.close();
} catch( IOException e ){
// never thrown in this case
}
...
随着数据不断地写入流中,
数据流
...
InputStream in = ... // an input stream
DataInputStream din = new DataInputStream( in );
try {
int custID = din.readInt();
String lastName = din.readUTF();
String firstName = din.readUTF();
long timestamp = din.readLong();
din.close();
}
catch( IOException e ){
// handle the error here
}
...
只有以
用来读取数据的应用程序必须知道原始数据的写入顺序,以便调用正确的方法。
...
OutputStream out = ... // an output stream
DataOutputStream dout = new DataOutputStream( out );
try {
dout.writeInt( 100 );
dout.writeUTF( "Smith" );
dout.writeUTF( "John" );
dout.writeLong( System.currentTimeMillis() );
dout.close();
}
catch( IOException e ){
// handle the error here
}
...
这些数据用 可调用两个方法来写字符串。您可以用
基本数据映射标准数据操作类可使基本数据映射变得容易..将数据写入记录库只需要将 ...
RecordStore rs = ... // a record store
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream( bout );
try {
dout.writeInt( 100 );
dout.writeUTF( "Smith" );
dout.writeUTF( "John" );
dout.writeLong( System.currentTimeMillis() );
dout.close();
byte[] data = bout.toByteArray();
rs.addRecord( data, 0, data.length );
}
catch( RecordStoreException e ){
// handle RMS error here
}
catch( IOException e ){
// handle IO error here
}
...
数据的读取是上述的步骤逆过程,它使用一个 ...
RecordStore rs = ... // a record store
int recordID = ... // the record to read
ByteArrayInputStream bin;
DataInputStream din;
try {
byte[] data = rs.getRecord( recordID );
bin = new ByteArrayInputStream( data );
din = new DataInputStream( bin );
int id = din.readInt();
String lastName = din.readUTF();
String firstName = din.readUTF();
long timestamp = din.readLong();
din.close();
... // process data here
}
catch( RecordStoreException e ){
// handle RMS error here
}
catch( IOException e ){
// handle IO error here
}
...
当写字符串时,需要注意 null 值。在大多数情况下,您会反而写一个空字符串。否则,您将需要用标记字节 (marker byte) 将 null 字符串和空字符串分别开来。
简单对象映射在许多情况下,您要保存的数据被封装到一个对象实例中。例如, package j2me.example;
// The contact information for a person
public class Contact {
private String _firstName;
private String _lastName;
private String _phoneNumber;
public Contact(){
}
public Contact( String firstName, String lastName,
String phoneNumber )
{
_firstName = firstName;
_lastName = lastName;
_phoneNumber = phoneNumber;
}
public String getFirstName(){
return _firstName != null ? _firstName : "";
}
public String getLastName(){
return _lastName != null ? _lastName : "";
}
public String getPhoneNumber(){
return _phoneNumber != null ? _phoneNumber : "";
}
public void setFirstName( String name ){
_firstName = name;
}
public void setLastName( String name ){
_lastName = name;
}
public void setPhoneNumber( String number ){
_phoneNumber = number;
}
}
如果类可以修改,那么引入持久存储的最简单的方法是添加方法,以实现对象和字节数组之间的相互映射: public void fromByteArray( byte[] data ) throws IOException {
ByteArrayInputStream bin = new ByteArrayInputStream(data);
DataInputStream din = new DataInputStream( bin );
_firstName = din.readUTF();
_lastName = din.readUTF();
_phoneNumber = din.readUTF();
din.close();
}
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream( bout );
dout.writeUTF( getFirstName() );
dout.writeUTF( getLastName() );
dout.writeUTF( getPhoneNumber() );
dout.close();
return bout.toByteArray();
}
那么,存储一个对象就成了一个简单的操作: ...
Contact contact = ... // the contact to store
RecordStore rs = ... // the record store to use
try {
byte[] data = contact.toByteArray();
rs.addRecord( data, 0, data.length );
}
catch( RecordStoreException e ){
// handle the RMS error here
}
catch( IOException e ){
// handle the IO error here
}
...
对象的检索也同样容易: ...
RecordStore rs = ... // the record store to use
int recordID = ... // the record ID to read from
Contact contact = new Contact();
try {
byte[] data = rs.getRecord( recordID );
contact.fromByteArray( data );
}
catch( RecordStoreException e ){
// handle the RMS error here
}
catch( IOException e ){
// handle the IO error here
}
...
如果类不可修改,如标准 package j2me.example;
import java.io.*;
import java.util.*;
// A helper class that converts transforms string
// vectors (vectors whose elements are instances of
// String or StringBuffer ) into byte arrays and vice-versa.
public class StringVectorHelper {
// Reconstitutes a vector from a byte array.
public Vector fromByteArray( byte[] data )
throws IOException {
ByteArrayInputStream bin =
new ByteArrayInputStream( data );
DataInputStream din = new DataInputStream( bin );
int count = din.readInt();
Vector v = new Vector( count );
while( count-- > 0 ){
v.addElement( din.readUTF() );
}
din.close();
return v;
}
// Transforms a vector into a byte array.
public byte[] toByteArray( Vector v )
throws IOException {
ByteArrayOutputStream bout =
new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream( bout );
dout.writeInt( v.size() );
Enumeration e = v.elements();
while( e.hasMoreElements() ){
Object o = e.nextElement();
dout.writeUTF( o != null ? o.toString() : "" );
}
dout.close();
return bout.toByteArray();
}
}
当然,您这里所做的一切都是为了开发一个对象串行化框架。一个完整的框架超出了本文的讨论范围,然而当您进行对象持久存储时,以下的问题还是值得仔细研究考虑的:
您可以避免这些问题,或者将它们的影响降低到最低,方法就是只保存和恢复原始 Java 数据类型和简单的、独立的对象。
使用数据流以上的示例直接处理字节数组。尽管它们在保存和恢复一组数据方面很方便,然而,当需要存储多组数据(例如,一组对象)时,对字节数组的处理就成为任务繁重的工作了。一个更好的方法是将字节数组的管理和数据的读写分开。例如,可以向 public void fromDataStream( DataInputStream din )
throws IOException {
_firstName = din.readUTF();
_lastName = din.readUTF();
_phoneNumber = din.readUTF();
}
public void toDataStream( DataOutputStream dout )
throws IOException {
dout.writeUTF( getFirstName() );
dout.writeUTF( getLastName() );
dout.writeUTF( getPhoneNumber() );
}
为方便起见,我们可以保持现有的 public void fromByteArray( byte[] data ) throws IOException {
ByteArrayInputStream bin = new ByteArrayInputStream(data);
DataInputStream din = new DataInputStream( bin );
fromDataStream( din );
din.close();
}
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream( bout );
toDataStream( dout );
dout.close();
return bout.toByteArray();
}
集中数据的读写以确保其一致性。
下一部分提要在本部分中,您已经学习了一些基本数据映射技术。在 第三部分 中,您将了解到一个更成熟的方法来管理持久存储数据,该方法可使您的应用程序存储和检索由多个包含不同数据类型的字段所组成的对象。 关于作者Eric Giguere 是来自 Sybase 子公司 iAnywhere Solutions 的一个软件开发人员,主要从事用于手持设备和无线计算的 Java 技术。他拥有 Waterloo 大学的 BMath 和 MMath 学位,并广泛撰写有关计算主题的文章。 数据库和 MIDP,第一部分:了解记录管理系统记录管理系统(Record Management System,RMS)是移动信息设备描述(Mobile Information Device Profile,MIDP)的一个主要子系统,是一种应用程序编程接口(API),为 MIDP 应用程序提供本地的、基于设备的数据持久存储功能。在各种 MIDP 设备大行其道的今天,RMS 是唯一可以实现本地数据存储的工具——极少设备支持传统的文件系统。可以设想一下,彻底地了解 RMS,对于编写任何依靠持久性本地数据的程序来说,是多么至关重要。 本文是一系列文章的第一篇。这些文章将探究 RMS,以及解答有关它在 MIDP 应用程序中使用情况的较重要的问题,例如,与外部数据源(如关系数据库)相互作用的问题。开始我们要讨论的是 RMS 提供一些什么内容,并编写几个简单的 RMS 调试诊断程序。 关键概念首先,要理解记录管理系统的一些关键概念。 记录顾名思义,RMS 是用来管理记录的系统。一条记录是一个单一的数据项。RMS 没有对放入记录的内容加以限制:记录可以是数字、字符串、数组和图像——任何一段连续字节可以描述的事物。如果您能将数据编译成二进制代码,并且具备相应的解码手段,那么您就能将其存入一条记录中,当然受系统分配的容量大小的限制。 许多 RMS 的初学者都对记录这个词感到困惑。“字段在什么地方?”他们奇怪系统是如何将单一记录细分为分散的数据序列。答案很简单:在RMS中,记录不包含任何字段。或者说得更准确些,一条记录只包含一个大小可变的二进制字段。这样,解释记录内容的任务就完全依靠应用程序来完成。RMS 只提供存储和惟一标识符。虽然这样分工导致应用程序趋于复杂化,但是它使得 RMS 小巧灵活——这是作为 MIDP 子系统的一项重要属性。 在 API 级别中,记录是简单的字节数组。 记录存储记录存储是记录的有序集合。记录不是独立的实体:每一条记录必须从属于一个记录存储,而且所有的记录存取都通过记录存储来实现。事实上,记录存储保证记录读写的自动运行,不会发生数据损坏。 在创建一条记录时,记录存储为其分配一个惟一的标识符。该标识符是称作记录 ID 的整数。加入记录存储的第一条记录的记录 ID 是 1,第二条的记录 ID 是 2,依此类推。记录 ID不是索引:记录删除后不会对现存的记录进行重新编号,也不会影响后面记录的记录 ID 值。 在 MIDlet 套件中使用名称来标记记录存储。一个记录存储名可以包括 1 到 32 位 Unicode 字符,而且在创建该记录存储的 MIDlet 套件中该名称必须惟一。在 MIDP1.0 中,记录存储不能被不同的 MIDlet 套件共享。在MIDP2.0 里面,则允许 MIDlet 套件与其他套件共享同一个记录存储,其中此记录存储由 MIDlet 套件的名称,销售商的名称以及记录存储自己的名称共同加以识别。 记录存储也具有时间戳记和版本信息,所以应用程序能够知道记录存储最后被修改的时间。为了进一步紧密跟踪,应用程序可以注册监听程序以便及时获知记录存储何时被修改。 在 API level 中,用 RMS 外观在我们看一些代码之前,先回顾一下几个有关 RMS 的关键信息。 存储容量限制基于记录的数据存储的有效存储空间总量,因设备的不同而不同。MIDP 规范要求设备为持久数据存储,保留至少 8k 非易失性存储空间。该规范没有对个别记录的大小加以限制,可是空间限制会随着设备的不同而发生改变。RMS 提供多种方式决定单条记录的大小,记录存储的总容量,以及保留多少空间用于数据存储。记住持久性存储器是共享的,是珍贵的资源,因此请节约使用。任何使用 RMS 的 MIDlet 套件,都应该通过在 JAR 的清单(manifest)文件和应用程序描述符中设置 MIDlet 数据大小(
需要指出,某些 MIDP 的实现需要定义其他的一些有关存储需求的属性——请查阅设备文档了解细节。 速度对持久性存储器操作所需的时间,通常都要比对易失性(非持久性)存储器进行相同操作所需的时间更长。特别是写数据,在某些平台上写数据会持续很长时间。为了提高性能,不是从 MIDlet 事件线程中来完成 RMS 操作,而是利用缓存频繁访问易失性存储器中的数据以保证用户接口反应迅速。 线程安全性RMS 操作具有很高的线程安全性,但对任何共享资源而言,各个线程仍必须协调对同一记录存储的数据读写操作。这种协调要求需要采用在不同 MIDlets 中运行的线程,因为在同一个 MIDlet 套件中记录存储是共享的。 异常一般说来,RMS API 中的方法除了会抛出诸如
注意,为了精简,这一系列文章中的代码里面的异常处理都被简化或者省略了。 使用 RMS剩下的文章内容讲述的是使用 RMS API 时对记录的一些基本操作。某些操作贯穿于一个工具类 RMSAnalyzer 的开发中,用于记录存储分析。 记录存储探究可以通过调用
注意,此数套件标识的只是自身 MIDlet 套件的记录存储。也就是说创建它们的那一个套件。MIDP 规范无论如何不包括列出其他 MIDP 套件记录存储的功能。在 MIDP 1.0 中,自身套件以外的记录存储是根本看不到的。在 MIDP 2.0,自己的套件可以将记录存储指派为可共享的,但其他 MIDlet 套件只有在知道其名称后才能使用它。 打开和关闭记录存储
销售商和套件的名称,必须与 MIDlet 套件的清单(manifest)文件和应用程序描述符所定义的名称相匹配。 完成对记录存储的操作之后,调用
每一个 创建记录存储
要执行记录存储的一次性初始化,请在打开记录存储后,立即检查
或者,要在某个记录存储一旦为空就重新初始化该记录存储,请检查
要创建共享的记录存储(只在 MIDP 2.0 中),请使用
当第二个参数为真且该记录存储已经不存在,则最后两个参数控制它的授权模式以及可写性。授权模式决定其他 MIDlet 套件能否访问该记录存储。有两种可能的模式分别为 注意自身 MIDlet 套件能够使用
实际上,最好用 添加与更新记录还记得记录是字节数组吧。使用
通过将第一个参数设为 可以用 不能批次添加或者更新记录:您必须在内存中作为字节数组的形式构建整个记录,而且使用一次调用来添加或更新记录。
您能通过调用 在第二篇文章中我们将着眼于将对象和其他数据转化为字节数组的策略。
第二种形式是从指定的偏移量开始,将数据复制到预分配的数组中并返回所复制的字节数量:
数组必须有足够的容量来容纳数据, 第二种形式在对于一系列记录的迭代操作时,进行最小化存储器分配工作很有帮助。例如,可以使用它和 但是,更好的方法是使用 用 一旦记录被删除,任何使用它的企图都会抛出 记录存储只有当其未打开时才能被删除,并且只能由自身 MIDlet 套件中的 MIDlet 来执行。
剩下还有几个 RMS 操作,它们都是属于 MIDlet 也能使用 第一篇以 默认情况下,分析程序转至 这种格式在使用 J2ME 无线工具包测试时很方便。为了在实际设备上测试,可以将分析结果发送到串口或者直接通过网络传输至 servlet。您可以通过定义一个自己的类来达到这个目的。这个类实现 附在本文之后的是一个称为 在第二篇中,我们将讨论数据映射。 February 01 2D游戏开发必备算法之_卡马克地图卷轴算法卡马克算法的思想:卡马克算法是在进行2D游戏地图卷动的算法中内存痕迹最小、效率适中的算法之一.其核心的思想就是把地图卷动过程中移出屏幕(不需要在显示的部分)所占用的buffer区域,绘制上新的需要图块,在往真实屏幕上绘制的时候,通过四次绘制buffer把完整的地图重现.
使用的方法:我们在实际的代码编写中按以下的方式进行.根据上面的基本思想,把地图分为四个块(十字形的将buffer划分为四块),用KaMaKeX和KaMaKeY来记录十字分区的中心坐标(相对于buffer的坐标,我把这个点叫卡马克分区点).当地图向右移动的时候这时把卡马克分区点的坐标X方向加上一个tile的width,然后在从现在的卡马克分区点的坐标Y开始绘制提取出来的tileID对应的图象,注意是从当前的卡马克分区点的坐标Y开始绘制,当超出buffer Height时在从0开始绘制直到结束,这样就完成了在水平方向上的更新.还有就是在水平移动卡马克分区点的时候是在buffer中循环的,也就是从0到buffer Width的一个循环过程,Y方向上完全一致. 最后是绘制过程,也就是将四个分区绘制出来,口诀就是左变友上变下,呵呵!掌握好卡马克算法对手游开发很有帮助的. 数独游戏算法public class ShuDu { /**存储数字的数组*/ static int[][] n = new int[9][9]; /**生成随机数字的源数组,随机数字从该数组中产生*/ static int[] num = {1,2,3,4,5,6,7,8,9}; public static void main(String[] args) { //生成数字 for(int i = 0;i < 9;i++){ //尝试填充的数字次数 int time = 0; //填充数字 for(int j = 0;j < 9;j++){ //产生数字 n[ i ][j] = generateNum(time); //如果返回值为0,则代表卡住,退回处理 //退回处理的原则是:如果不是第一列,则先倒退到前一列,否则倒退到前一行的最后一列 if(n[j] == 0){ //不是第一列,则倒退一列 if(j > 0){ j-=2; continue; }else{//是第一列,则倒退到上一行的最后一列 i--; j = 8; continue; } } //填充成功 if(isCorret(i,j)){ //初始化time,为下一次填充做准备 time = 0; }else{ //继续填充 //次数增加1 time++; //继续填充当前格 j--; } } } //输出结果 for(int i = 0;i < 9;i++){ for(int j = 0;j < 9;j++){ System.out.print(n[j] + " "); } System.out.println(); } } /** * 是否满足行、列和3X3区域不重复的要求 * @param row 行号 * @param col 列号 * @return true代表符合要求 */ public static boolean isCorret(int row,int col){ return (checkRow(row) & checkLine(col) & checkNine(row,col)); } /*J2meMobile社区*/ /** * 检查行是否符合要求 * @param row 检查的行号 * @return true代表符合要求 */ public static boolean checkRow(int row){ for(int j = 0;j < 8;j++){ if(n[row][j] == 0){ continue; } for(int k =j + 1;k< 9;k++){ if(n[row][j] == n[row][k]){ return false; } } } return true; } /** * 检查列是否符合要求 * @param col 检查的列号 * @return true代表符合要求 */ public static boolean checkLine(int col){ for(int j = 0;j < 8;j++){ if(n[j][col] == 0){ continue; } for(int k =j + 1;k< 9;k++){ if(n[j][col] == n[k][col]){ return false; } } } return true; } /** * 检查3X3区域是否符合要求 * @param row 检查的行号 * @param col 检查的列号 * @return true代表符合要求 */ public static boolean checkNine(int row,int col){ //获得左上角的坐标 int j = row / 3 * 3; int k = col /3 * 3; //循环比较 for(int i = 0;i < 8;i++){ if(n[j + i/3][k + i % 3] == 0){ continue; } for(int m = i+ 1;m < 9;m++){ if(n[j + i/3][k + i % 3] == n[j + m/3][k + m % 3]){ return false; } } } return true; } /** * 产生1-9之间的随机数字 * 规则:生成的随机数字放置在数组8-time下标的位置,随着time的增加,已经尝试过的数字将不会在取到 * 说明:即第一次次是从所有数字中随机,第二次时从前八个数字中随机,依次类推, * 这样既保证随机,也不会再重复取已经不符合要求的数字,提高程序的效率 * 这个规则是本算法的核心 * @param time 填充的次数,0代表第一次填充 * @return */ public static int generateNum(int time){ //第一次尝试时,初始化随机数字源数组 if(time == 0){ for(int i = 0;i < 9;i++){ num = i + 1; } } //第10次填充,表明该位置已经卡住,则返回0,由主程序处理退回 if(time == 9){ return 0; } //不是第一次填充 //生成随机数字,该数字是数组的下标,取数组num中该下标对应的数字为随机数字 int ranNum = (int)(Math.random() * (9 - time)); //把数字放置在数组倒数第time个位置, int temp = num[8 - time]; num[8 - time] = num[ranNum]; num[ranNum] = temp; //返回数字 return num[8 - time]; } } |
|
|