2.1 MIDlet(Mobile Information Devices let) 移动信息设备小程序 ... 2 2.5 界面开发 (javax.microedition.lcdui) 3 2.12.6 TextField 类似 TextBox. 6 2.13 ItemCommandListener(item 事件 ) 6 7 RMS 编程 (Record Management System) 8 1 体系介绍和环境配置
1.1 J2ME 分为两类:1 ) CDC(Connected Device Configuration) 如 PDA CVM 2 ) CLDC(Connected Limeted Device Configuration) 如手机 KVM(Kilo Virtual Machine)
1.2 J2ME 体系架构 ( 底层— > 高层 )底层操作系统—》配置 (Configurations) —》描述 (Profiles) —》可选包 注:手机属于 CLDC 和 MIDP(Mobile Information Device Profile)
1.3 环境搭建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
2 高级界面开发
2.1 MIDlet(Mobile Information Devices let) 移动信息设备小程序
2.2 MIDlet 三种状态a) 运行状态 ,startApp() b) 暂停状态 ,pauseApp(), 通过 notifyPaused() 可进入该状态 c) 销毁状态 ,destroyApp(), 通过 notifyDestroyed() 可进入该状态 注:程序运行调用构造函数一次,在运行状态和暂停状态可相互切换,关闭则进入销毁状态
2.3 JAD 文件描述具体运行的配置以及 JAR 文件所在位置
2.4 MANIFEST描述 MIDlet Suite 的配置,扩展名为 .mf
2.5 界面开发 (javax.microedition.lcdui)1) 界面组件 Displayable 及子类 2) 把组件添加到界面 Display 类 Display d = Display.getDisplay(this); d.setCurrent(Displayable dis); 3)Command 类 不同于 Displayable ,只能用 Displayable.addCommand(Command c);
2.6 多个按钮加入界面的排布规律1 )不同种类按钮, WTK 优先级排序: ITEM,SCREEN,OK,HELP,BACK,EXIT,CANCEL,STOP 2 )同一种类按钮,在构造函数内划分优先级,越小越优先 3 ) BACK,CANCEL,EXIT,STOP 倾向抢占左方,优先级为 BACK,CANCEL,EXIT,STOP 4 )只在 WTK 满足这样的规律
2.7 Command 事件响应1 )编写一个类实现 CommandListener ( javax.microedition.lcdui ) 2 )用 Displayable.setCommandListener() 方法将 Displayable 与该类绑定(与 J2SE 不同)
2.8 List1) 三种类型: implicit 互斥, exclusive 另一种互斥, multiple 多选 2 )操作: 添加项 append() 删除项 delete() deleteAll() 修改项 set() 插入项 insert() 得到项内容 getString() getImage() 设置项字体 setFont() 获取所选项 getSelectedIndex() list 总共多少项 size()
注: 获得多选项 1 )遍历每一项判断是否选中 2 )利用 getSelectedFlags() 判断那些项被选中
List 内置一 command 专门为 implicit 模式,可通过 SELECT_COMMAND 获得
2.9 TextBox1) 创建 TextBox 时用到 TextField 的常量进行约束 2) 操作: 获得光标位置 getCaretPosition() 从 0 开始 获取所有文本 getString() 插入文本 insert() 替换文本 setString() 删除文本 delete() 设置初始输入法 setInitialInputMode() 获取输入文字个数 size()
2.10 Ticker 滚动条Displayable.setTicker();
2.11 Alter 1 ) Display.setCurrent() 2 ) alterType alarm 提醒 confirmation 确认 error 错误 info 通知 warning 警告 3 ) setTimeout() 设置持续时间 setTimeout(Alter.FOREVER) 永远不消失
2.12 表单元素1 ) Form.append(item) 2 ) Display.setCurrentItem(item) 如有多个选择,设置为默认选择,但是在之前必须先把 item 添加到 Form
2.12.1 ChoiceGroup类型: Choice.EXCLUSIVE 单选, Choice.MULTIPLE 复选, Choice.POPUP 下拉列表
2.12.2 CustomItem用户自定义 Item ,必须继承自该抽象类
2.12.3 DateField1 )三种模式 DateField.DATE 只显示或修改日期 DateField.TIME 只显示或修改时间 DateField.DATE_TIME 显示或修改日期时间 2) getDate() setDate()
2.12.4 Gauage 进度条1) interactive 参数:是否可以修改进度条的值 2 ) setValue() getValue()
2.12.5 ImageItem1 )参数 layout :布局 参数 altText :图片加载失败时显示的文字 参数 appearanceMode :图片显示的样式 s 2.12.6 TextField 类似 TextBox
2.12.7 StringItem 类似 Label
2.13 ItemCommandListener(item 事件 )适用于表单上将某个表单元素和命令按钮进行绑定 步骤 1) implements ItemCommandListener 步骤 2 ) item.addCommand(Command) 步骤 3) item.setItemCommandListener(ItemCommanListener)
2.14 ItemStateListener某个表单元素状态改变时触发事件 步骤 1 ) implements ItemStateListener 步骤 2 ) Form.setItemStateListener(ItemStateListener)
3 数值运算 Mathceil 不小于一个数字的最小整数 eg:ceil(1.3)=2 floor 不大于一个数字的最大整数 eg:floor(1.8)=1 toDegrees 弧度转角度 toRadians 角度转弧度
4 定时器每隔一段时间做一件事情 步骤 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); 某段时间之后触发开始执行
5 手机震动和闪烁震动: Display.flashBacklight(int) int 为持久时间 闪烁: Display.vibrate(int) int 为持久时间
6 画布开发 Canvas (低级界面)步骤 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() 判断手机是否支持指针拖动
7 RMS 编程 (Record Management System)
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, 如果数据太大 , 考虑用多个记录集
8 网络编程
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);
9 Http 编程
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();
10 GameAPI
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);
11 代码优化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 释放所有资源 |
|