1.1 J2ME 分为两类: ... 1
1.2 J2ME 体系架构 ( 底层— > 高层 ) 2
1.3 环境搭建 ... 2
2 高级界面开发 ... 2
2.1 MIDlet(Mobile Information Devices let) 移动信息设备小程序 ... 2
2.2 MIDlet 三种状态 ... 2
2.3 JAD 文件 ... 3
2.4 MANIFEST. 3
2.5 界面开发 (javax.microedition.lcdui) 3
2.6 多个按钮加入界面的排布规律 ... 3
2.7 Command 事件响应 ... 3
2.8 List 3
2.9 TextBox. 4
2.10 Ticker 滚动条 ... 4
2.12 表单元素 ... 5
2.12.1 ChoiceGroup. 5
2.12.2 CustomItem.. 5
2.12.3 DateField. 5
2.12.4 Gauage 进度条 ... 5
2.12.5 ImageItem.. 5
2.12.6 TextField 类似 TextBox. 6
2.12.7 StringItem 类似 Label 6
2.13 ItemCommandListener(item 事件 ) 6
2.14 ItemStateListener 6
3 数值运算 Math. 6
4 定时器 ... 6
5 手机震动和闪烁 ... 7
6 画布开发 Canvas (低级界面) ... 7
7 RMS 编程 (Record Management System) 8
8 网络编程 ... 9
9 Http 编程 ... 10
10 GameAPI 11
11 代码优化 ... 13
1 ) CDC(Connected Device Configuration) 如 PDA CVM
2 ) CLDC(Connected Limeted Device Configuration) 如手机 KVM(Kilo Virtual Machine)
底层操作系统—》配置 (Configurations) —》描述 (Profiles) —》可选包
注:手机属于 CLDC 和 MIDP(Mobile Information Device Profile)
1 ) JDK1.6 java.sun.com/j2se
2 ) WTK2.5.2 java.sun.com/j2me
WTK 重要目录介绍
apps :例子及源码 bin :命令行工具 docs :文档 lib :类库
3 )插件 EclipseMe1.7.7 www.eclipseme.org 分别与 eclipse 和 WTK 绑定
4 ) wtk 提供了四种手机模拟器,需要特殊模拟器可以到相应手机厂商网站下载
Nokia : www.forum.nokia.com
Moto : developer.motorola.com
a) 运行状态 ,startApp()
b) 暂停状态 ,pauseApp(), 通过 notifyPaused() 可进入该状态
c) 销毁状态 ,destroyApp(), 通过 notifyDestroyed() 可进入该状态
注:程序运行调用构造函数一次,在运行状态和暂停状态可相互切换,关闭则进入销毁状态
描述具体运行的配置以及 JAR 文件所在位置
描述 MIDlet Suite 的配置,扩展名为 .mf
1) 界面组件 Displayable 及子类
2) 把组件添加到界面 Display 类
Display d = Display.getDisplay(this);
d.setCurrent(Displayable dis);
3)Command 类
不同于 Displayable ,只能用 Displayable.addCommand(Command c);
1 )不同种类按钮, WTK 优先级排序:
ITEM,SCREEN,OK,HELP,BACK,EXIT,CANCEL,STOP
2 )同一种类按钮,在构造函数内划分优先级,越小越优先
3 ) BACK,CANCEL,EXIT,STOP 倾向抢占左方,优先级为 BACK,CANCEL,EXIT,STOP
4 )只在 WTK 满足这样的规律
1 )编写一个类实现 CommandListener ( javax.microedition.lcdui )
2 )用 Displayable.setCommandListener() 方法将 Displayable 与该类绑定(与 J2SE 不同)
1) 三种类型: implicit 互斥, exclusive 另一种互斥, multiple 多选
2 )操作:
添加项 append()
删除项 delete() deleteAll()
修改项 set()
插入项 insert()
得到项内容 getString() getImage()
设置项字体 setFont()
获取所选项 getSelectedIndex()
list 总共多少项 size()
注:
获得多选项
1 )遍历每一项判断是否选中
2 )利用 getSelectedFlags() 判断那些项被选中
List 内置一 command 专门为 implicit 模式,可通过 SELECT_COMMAND 获得
1) 创建 TextBox 时用到 TextField 的常量进行约束
2) 操作:
获得光标位置 getCaretPosition() 从 0 开始
获取所有文本 getString()
插入文本 insert()
替换文本 setString()
删除文本 delete()
设置初始输入法 setInitialInputMode()
获取输入文字个数 size()
Displayable.setTicker();
2.11 Alter
1 ) Display.setCurrent()
2 ) alterType
alarm 提醒 confirmation 确认 error 错误 info 通知 warning 警告
3 ) setTimeout() 设置持续时间 setTimeout(Alter.FOREVER) 永远不消失
1 ) Form.append(item)
2 ) Display.setCurrentItem(item) 如有多个选择,设置为默认选择,但是在之前必须先把 item 添加到 Form
类型: Choice.EXCLUSIVE 单选, Choice.MULTIPLE 复选, Choice.POPUP 下拉列表
用户自定义 Item ,必须继承自该抽象类
1 )三种模式
DateField.DATE 只显示或修改日期
DateField.TIME 只显示或修改时间
DateField.DATE_TIME 显示或修改日期时间
2) getDate() setDate()
1) interactive 参数:是否可以修改进度条的值
2 ) setValue() getValue()
1 )参数 layout :布局
参数 altText :图片加载失败时显示的文字
参数 appearanceMode :图片显示的样式
s
适用于表单上将某个表单元素和命令按钮进行绑定
步骤 1) implements ItemCommandListener
步骤 2 ) item.addCommand(Command)
步骤 3) item.setItemCommandListener(ItemCommanListener)
某个表单元素状态改变时触发事件
步骤 1 ) implements ItemStateListener
步骤 2 ) Form.setItemStateListener(ItemStateListener)
ceil 不小于一个数字的最小整数 eg:ceil(1.3)=2
floor 不大于一个数字的最大整数 eg:floor(1.8)=1
toDegrees 弧度转角度
toRadians 角度转弧度
每隔一段时间做一件事情
步骤 1 :定义一个类,继承 TimerTask ,重写 run 方法
步骤 2 :定义一个 Timer
schedule(TimerTask task, Date time); 某时刻触发
schedule(TimerTask task, Date firstTime, long period); 某个时刻开始执行,指定重复执行的周期,单位是毫秒
schedule(TimerTask task, long delay); 某段时间之后触发
schedule(TimerTask task, long delay, long period); 某段时间之后触发开始执行
震动: Display.flashBacklight(int) int 为持久时间
闪烁: Display.vibrate(int) int 为持久时间
步骤 1 :写一个 class 继承 Canvas ,必须重写 paint ( Graphics )
步骤 2: Display.setCurrent ( Canvas )
showNotify ()画布放在界面最前端显示时自动调用
hideNotify ()画布隐藏时自动调用
paint ( Graphics )画布出现后自动调用
setFullScreenMode ( boolean )设置全屏
getHeight (), getWidth () 获取高度和宽度
Graphics 方法:
setColor() 设置绘图颜色
setStrokeStyle() 设置划线样式 SOLID 实线 DOTTED 虚线
drawLine() 画直线
drawRect()/fillRect() 画矩形 / 实心矩形
drawRoundRect()/fillRoundRect() 画圆角矩形 / 圆角实心矩形
drawArc()/fillArc() 画弧线 / 填充弧线
fillTriangle() 填充三角形
repaint() 强制重画
setFont() 修改字体
drawString() 画字符串
注:确定定位点 LEFT,HCENTER,RIGHT | BUTTOM,TOP,BASELINE
将字画在屏幕正中,要用到 Font.stringWidth(String),Font.getHeight()
drawImage() 画图片
drawRegion() 截取图片的一部分画到另外一个地方去
按键事件:
keyPressed(int keyCode) 按下某个键
keyReleased(int keyCode) 释放某个键
keyRepeated(int keyCode) 一直按着某个键
注:除 0-9 键外其他键被认为为特殊键(游戏键),特殊键不能直接通过 keyCode 获得,要通过 getGameAction(keyCode) 转换才能得到相应值,反之可以通过 getKeyCode(action) 将 action 转换为 keycode
指针事件:
pointerDragged(int x, int y)
pointerPressed(int x, int y)
pointerReleased(int x, int y)
注: x,y 为指针当前位置
hasPointerEvents() 判断手机是否支持指针按下,释放
hasPointerMotionEvents() 判断手机是否支持指针拖动
1)javax.microedition.rms
2)RecordStore 相当于 表
4) 数据文件路径在:用户名 /j2mewtk/appdb/temp.DefaultColorPhone** 下面的 *.db 文件
3) 记录集操作
打开记录集 RecordStore.openRecordStore()
得到记录集大小 RecordStore.getSize();
关闭记录集 RecordStore.closeRecordStore();
列出当前所有记录集 RecordStore.listRecordStores();
删除记录集 RecordStore.deleteRecordStore();
获取记录集可用空间 RecordStore.getSizeAvialable();
5)RecordStore 记录操作(每条记录都有 ID ,第一条记录 ID 为 1 )
添加记录 addRecord()
得到当前记录条数 getNumRecords()
根据 ID 获得记录 getRecord()
根据 ID 获得记录字节数 getRecordSize()
修改记录 setRecord()
删除记录 deleteRecord()
获取下一条要插入的记录 ID getNextRecordID()
6) 将对象写入 RMS
自己写方法将对象转为字节数组
DataOutputStream
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.writeUTF(this.cname);
dos.writeUTF(this.phone);
dos.writeUTF(this.age);
baos.toByteArray();
7) 遍历记录
RecordStore rs = RecordStore.openRecordStore();
RecordEnumeration re = rs.enumerateRecords();
while(re.hasNextElement())
{
re.nextRecord();
}
8) 记录监听 (implements RecordListener)
记录添加时触发 recordAdded(RecordStore, recordid);
记录修改是触发 recordChanged(RecordStore, recordid);
记录删除时触发 recordDeletedRecordStore, recordid);
绑定监听器 rs.addRecordListener(RecordListener);
9) 数据过滤
implements RecordFilter,
实现 match 函数 ,
用枚举方法遍历 , 传入类的对象
10) 数据排序
implements RecordComparator,
实现 compare 方法 , 返回指定值
RecordComparator.PRECEDES: 记录 1 在记录 2 前面
RecordComparator.FOLLOWS: 记录 1 在记录 2 后面
RecordComparator.EQUIVALENT: 记录 1= 记录 2,
用枚举方法遍历 , 传入类的对象
11) 注意事项
a. 可以修改 MF 或者 JAD 文件中的 MIDlet-Data-Size 属性来改变 RMS 的最小存储字节数 , 首选 JAD
b. 一个记录集的容量有限 , 约 100K, 如果数据太大 , 考虑用多个记录集
1)Socket 编程 (javax.microedition.io)SocketConnection
a. 服务器端
// 监听 9999 端口
ServerSocketConnection ssc =
(ServerSocketConnection)Connector.open("socket://:9999");
ssc.getLocalAddress(); // 获取本地 IP 地址
ssc.getLocalPort(); // 获取本地端口
// 等待客户端连接 , 如果没有客户端连接则阻塞
SocketConnection sc = (SocketConnection)ssc.acceptAndOpen();
sc.getAddress(); // 获得客户端 IP 地址
DataInputStream dis = sc.openDataInputStream();
String str = dis.readUTF(); // 如果没有读到内容则死等
b. 客户端
// 连接到服务器端 , 与服务器端的 sc 是同一对象
SocketConnection sc = (SocketConnection)Connector.open("socket://127.0.0.1:9999");
DataOutputStream dos = sc.openDataOutputStream();
dos.writeUTF(String);
2)UDP 编程 (javax.microedition.io.UDPDatagramConnection)
a. 服务器端
// 监听 9999 端口
int max = 255;
UDPDatagramConnection udc =
(UDPDatagramConnection)Connector.open("datagram://:9999");
// 接收数据报
Datagram dg = udc.newDatagram(max);
udc.receive(dg);
byte[] data = dg.getData();
String str = new String(data, 0, dg.getLength());
b. 客户端
UDPDatagramConnection udc =
(UDPDatagramConnection)Connector.open("datagram://127.0.0.1:9999");
// 发送数据报
String str = " 你好 ";
Datagram dg = udc.newDatagram(str.getBytes(), str.getBytes().length);
udc.send(dg);
HttpConnection hc = (HttpConnection)Connector.open("http://localhost:9999/test.html");
hc.getResponseCode(); // 返回代码,如 500 , 404
hc.getResponseMessage(); // 返回信息
hc.getHost();
hc.getPort();
hc.getProtocol();
hc.getURL();
hc.getQuery(); // 得到查询字符串
hc.getRequestMethod(); // 得到请求方法 Post , Get
hc.setRequestMethod(String); // 设置请求方法
hc.getLength(); // 获得网页大小
与服务器交互:
hc.openDataInputStream();/hc.openInputStream();
hc.openDataOutputStream();/hc.openOutputStream();
1) javax.microedition.lcdui.game 提高游戏性能
2) GameCanvas :游戏画布,比普通画布更加适合游戏开发
a) 基本结构
public MyGameCanvas extends GameCanvas implements Runnable{
public MyGameCanvas(){
//true 特殊键被禁用,通过 getKeyStates() 获得按下哪些游戏键
super(true);
}
public void run(){}
}
b) 可以通过 getGraphics() 得到画笔 , 不用写 paint() 函数 , 不用 repaint() 开销 ,
flushGraphics() 将缓冲区里的图像显示在屏幕上
3) Layer :图层,表示画布上的某个可视的物体,是抽象类
a)Sprite :可以充当游戏中的具体角色,一般用于运动角色,如子弹,汽车等
* 重要方法
move(int x, int y); // 移动相对位置
setPosition(int x, int y); // 移动绝对位置
Sprite(Image image);
Sprite(Image image, int frameWidth, int frameHeight);
paint(Graphics g); // 将图层画到屏幕上
* 悬挂
defineReferencePixel(int x, int y); // 定义图层悬挂点
setRefPixelPosition(int x, int y); // 定义悬挂点在屏幕的某个位置
setTransform(int transform) // 旋转
* 碰撞
// 定义一个矩形的不可碰撞区域
defineCollisionRectangle(int x, int y, int width, int height);
// 判断是否和另外一个 Sprite 碰撞,参数 2 为 true ,则认为不透明点发生碰撞才算碰撞
collidesWith(Sprite s, boolean pixelLevel);
// 判断是否和 TiledLayer 发生碰撞
collidesWith(TiledLayer t, boolean pixelLevel);
* 带动画的角色
// 切割图片原则:首先走行,一行走完,取下一列,编号从 0 开始
Sprite(Image image, int frameWidth, int frameHeight);
// 得到总帧数
int getRawFrameCount();
void nextFrame()/void preFrame()/void setFrame(int sequenceIndex);
// 设置帧的顺序
setFrameSequence(int[] sequence);/int getFrameSequenceLength();
// 设置图片
setImage(Image img, int frameWidth, int frameHeight);
b)TiledLayer :可以充当游戏中的具体角色,一般用于环境角色,如地图等
* 构造函数
// 将图片用 tileWidth , tileHeight 分割,指定将要填充的列数和行数
// 图片小块 index 从 1 开始
TiledLayer(int columns, int rows, Image image, int tileWidth, int tileHeight)
void patint(Graphics g);
// 将某个图片小块填入相应的位置
void setCell(int col, int row, int tileIndex);
// 得到某行某列图片的 Index
int getCell(int col, int row);
int getCellHeight();/int getCellWidth();
int getColumns();/int getRows();
// 用一个图片小块填充整个网格
void fillCells(int col, int row, int numCols, int numRows, int tileIndex);
// 修改图片
void setStaticTileSet(Image image, int tileWidth, int tileHeight);
* 技巧
应将不同的物体弄成不同的图层,便于碰撞检测
4) LayerManager: 管理图层的变换
void append(Layer l);
void remove(Layer l);
// 设置窗口可视部分
void setViewWindow(int x, int y, int width, int height);
// 将所有图层统一画出来
void paint(Graphics g, int x, int y);
1) 微观编程
* 除法优化 / 改为 >>
* 局部变量赋值性能高于全局变量
* 使用 switch 代替 if else, 可读性比较好
2) 字符串
* String str = "China";
* s.length()==0
* (StringBuffer)sb.append(',');
* 用 StringBuffer 比较好
3) 异常处理 , 尽量少用
4) 内部类需要额外开销
5) 引用不用后置空
连接最终要关闭
6) Midlet 各函数功能分配
* 成员变量生成和构造函数 , 在生命周期中执行一次 , 一般完成资源分配 , 对象创建
* 一般在定义时创建对象 , 或在构造函数中创建对象
* pause 函数运行之后如果再继续 ,startApp 会运行 , 所以可以在 pause 函数中释放一些资源 , 在 startApp 中获得
* destroyApp 释放所有资源