代码移植
以下将详细讲解将J2ME的黑白棋移植到中国移动统一开发环境(以下简称UDE)中,从而比较二者的区别和联系。
在《UDE_helloword》中,我们已经详细介绍了UDE开发应用程序的基本结构,现在我们要将网络上开源的项目黑白棋用 UDE 来实现。
(1) J2ME vs UDE
J2ME的高级用户界面比较鸡肋,在现在大多数的应用里都看不到,多数稍微复杂点的界面都是手工画,或是用一些开源的高级UI库。而UDE的用户界面则完全是由图片构成,开发者可根据自己喜好,任意更换图片,改变界面样式风格。接下来我们简单比较二者的区别,为黑白棋项目从J2ME到UDE的移植做准备。
1)平台
J2ME:开发平台
UDE:开发平台
2)工程结构
J2ME:
res:资源文件
src:源代码
UDE:
src:源代码
app\css:css样式文件
app\img:图片文件
app\xml:界面显示文件
config.xml:项目配置文件
3) 安装包
J2ME:
jad,jar
UDE:
jar,sisx,apk
4) 代码结构
J2ME:
MIDlet,Canvas,采用继承的方式,只有一个MIDlet,一般只有一个Canvas
UDE:
Api,Main,采用继承的方式,Api为主要继承父类,一般只有一个Main
5)入口程序
J2ME:
MIDlet类
UDE:
Main类
6)主程序结构
J2ME:
package com.deaboway.j2me;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
public class MyMidlet extends MIDlet {
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
protected void startApp() throws MIDletStateChangeException{
}
}
UDE:
package cn.com.talkweb.talk;
import com.talkweb.j2me.core.Api;
import com.talkweb.j2me.ui.core.UiApi;
public class Main extends Api {
public static void main(){
}
}
7)生命周期-开始
J2ME:
startApp(),活动状态,启动时调用,初始化。
UDE:
main(),启动时调用。
8)生命周期-暂停
J2ME:
pauseApp(),暂停状态,如来电时,调用该接口。
UDE:
无。
9)生命周期-销毁
J2ME:
destroyApp(),销毁状态,退出时调用。
UDE:
无。
10) 刷新
J2ME:
高级UI组件由内部刷新实现。低级UI,canvas中通过调用线程结合repaint()来刷新,让线程不断循环。低级UI架构可以用MVC方式来实现,建议使用二级缓存。
UDE:
可调用Api.forward()方法进行页面的跳转来刷新,或者使用UiApi.repaint()方法来实现刷新。
11) 绘画
J2ME:
Displayable类。J2me中所有可显示的组件都是直接或间接的继承了Displayable,直接的是Canvas和Screen。不同的继承导致了低级UI和高级UI的区别。J2me中现成的UI组件都是直接或者间接继承了Screen。只要调用Display.getDisplay(MIDLetinstan).setCurrrent(Displayabledisp),就可以把组件显示到手机界面上。切换界面的时候也可以使用该接口。
UDE:
UDE中所有的组件都定义在xml文件当中,如需对组件的样式进行修改,需在css文件中给出样式定义。界面的绘制完全是加载css样式文件后,根据xml的中组件的定义和排列,生成用户界面。
12)画笔
J2ME:
高级UI组件由内部刷新实现。低级UI,canvas中通过调用线程结合repaint()来刷新,让线程不断循环。低级UI架构可以用MVC方式来实现,建议使用二级缓存。
UDE:
无。
13)全屏
J2ME:
Canvas中SetFullScreenMode()。
UDE:
默认全屏。
14)获得屏幕尺寸
J2ME:
Canvas类的getHeight()和getWidth()
UDE:
分辨率定制,无法获得。
15) 可绘区域
J2ME:
int clipX = g.getClipX();
int clipY = g.getClipY();
int clipWidth = g.getClipWidth();
int clipHeight = g.getClipHeight();
g.clipRect(x, y, width, height);
g.setClip(clipX, clipY, clipWidth, clipHeight);//释放当前状态
UDE:
整个屏幕均为可绘区域,需安装分辨率进行区分。
16)清屏操作
J2ME:
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
UDE:
UiApi.forward("/xml/main.xml");
17)双缓冲
J2ME:
Image bufImage=Image.createImage(bufWidth, bufHeight);
Graphics bufGraphics=bufImage.getGraphics();
UDE:
无此概念
18) 图片类
J2ME:
Image类,Image.createImage(path);
UDE:
在xml页面中使用<picture>logo.png</picture>组件。
19) 绘制矩形
J2ME:
drawRect的后两个参数为宽度和高度。
UDE:
无此概念,必须使用png图片绘制。
20)按键
J2ME:
keyPressed()
keyRepeated()
keyReleased()
UDE:
onAction="exit()"
shortcuts="1=exit|2=login"
21)键值
J2ME:
Canvas.LEFT…
UDE:
left…
22)触笔
J2ME:
pointerPressed(),pointerReleased(),pointerDragged()
UDE:
同按键效果,触屏手机默认支持。
23)数据存储
J2ME:
Record Management System (RMS)
UDE:
Record Management System (RMS)
24)连接
J2ME:
从Connector打开,可以直接在Connector.Open时设置连接是否可读写,以及超时设置。
UDE:
Api.doPost(url, request, call);通过请求路径,请求参数和回调函数方式进行连接,连接返回数据的处理和超时情况,均在call回调函数中解决。
25)游戏开发包
J2ME:
javax.microedition.lcdui.game.*;
GameCanvas/Layer/LayerManager/ Sprite/TiledLayer
UDE:
无专门针对游戏的开发包。
26) 音效
J2ME:
Player s=Manager.createPlayer(InputStream);
s.prepare();//创建
s.start();//播放
s.stop();//暂停
s.stop();//关闭
s.release();//释放
UDE:
Api.invokeApi("UserApiImpl.startSound",new Object[]{"/1.mid"});
27)显示文本
J2ME:
String
UDE:
在xml页面中使用<text></text>组件。
28)打印信息
J2ME:
System.out.println()
UDE:
Api.info("");
(2) 迁移关键点
1)基础类和结构
J2ME的所有界面类均抛弃,转为UDE的xml界面,标准J2SE算法代码均抛弃,重写为UDE语法支持的算法代码。J2ME控件样式均抛弃,所有控件均切图,在css样式文件中定义。代码结构和逻辑均需要重新开发和处理。
a.资源获取,直接在xml中使用各种组件获取,下为主页面:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 屏幕元素,也就是J2ME中的画布 -->
<screen style="align:center;layout:inlinelayout(false,fill)">
<!--容器元素,类似样式中的DIV元素-->
<container style="layout: gridlayout(8,; " nearfocus="true">
<!--按钮元素,在黑白棋游戏中,表示一个棋子,棋盘大小8X8-->
<button id="1_1"><picture id="1_1_p"></picture></button>
<button id="1_2"><picture id="1_2_p"></picture></button>
<button id="1_3"><picture id="1_3_p"></picture></button>
<button id="1_4"><picture id="1_4_p"></picture></button>
<button id="1_5"><picture id="1_5_p"></picture></button>
<button id="1_6"><picture id="1_6_p"></picture></button>
<button id="1_7"><picture id="1_7_p"></picture></button>
<button id="1_8"><picture id="1_8_p"></picture></button>
<!--中间部分内容省略-->
</container>
<!--文本元素 -->
<text id="txtWhite"></text>
<text id="txtBlack"></text>
<text id="txtNextSet"></text>
<!--菜单元素 -->
<screenSecondMenu>退出</screenSecondMenu>
</screen>
b.初始化棋盘:
public class Game
{
//定义一个变量,用来判断轮到谁下棋,初始化为黑棋
public static int m_turn = AllDef.BLACK;
//当前状态为准备状态
public int m_state = AllDef.READY;
//定义棋盘盘面,初始化为-1
public static int[][] m_board = {{-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1}, {-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1}};
public Game()
{
}
}
c.放置棋子状态的核心代码:
public class setState {
public static void resultPage(int w,int b,String winner){
Api.info("resultPage----------------");
UiApi.forward("/xml/result.xml");
WidgetUtil.setText("txtWhiteScore", "白棋数是:"+w);
WidgetUtil.setText("txtBlackScore", "黑棋数是:"+b);
if("BLACK".equals(winner)){
WidgetUtil.setText("txtWinner", "黑棋赢了!");
}else{
WidgetUtil.setText("txtWinner", "白棋赢了!");
}
}
//设置页面显示样式效果
public static void setUiState(String id,String state){
String btnId=null;
btnId=id;
String btnState=null;
btnState=state;
if("white".equals(btnState)){
WidgetUtil.UiInvoke(btnId+"_p", "setStyleClass", new String[]{"onwhitestate"});
}else if("none".equals(btnState)){
WidgetUtil.UiInvoke(btnId+"_p", "setStyleClass", new String[]{"normalstate"});
}else{
WidgetUtil.UiInvoke(btnId+"_p", "setStyleClass", new String[]{"onblackstate"});
}
}
//设置走棋后的棋盘页面
public static void next(int xp,int yp){
//如果当前是黑棋
if( AllDef.BLACK == Game.m_turn )
{
if(Player.setChess(xp, yp))
{
if(Game.m_turn == AllDef.BLACK)
Game.m_turn = AllDef.WHITE;
else
Game.m_turn = AllDef.BLACK;
}
}
//如果当前是白棋
if( AllDef.WHITE == Game.m_turn )
{
WidgetUtil.UiInvoke("whiter_p", "setStyleClass", new String[]{"whiterhover"});
WidgetUtil.UiInvoke("arrows_p", "setStyleClass", new String[]{"arrowswhiter"});
WidgetUtil.UiInvoke("blacker_p", "setStyleClass", new String[]{"blacker"});
int xx[] = PlayerWhite.aiXY();
if(PlayerWhite.setChess(xx[0], xx[1]))
{
if(Game.m_turn == AllDef.BLACK)
Game.m_turn = AllDef.WHITE;
else
Game.m_turn = AllDef.BLACK;
}
}
}
//页面显示
public static void showScreen(){
for(int x=1; x<=8; x++){
for(int y=1; y<=8; y++){
if(-1 == Player.getChess(x, y)){
setState.setUiState(x+"_"+y, "none");
continue;
}else if(AllDef.BLACK == Player.getChess(x, y)){
setState.setUiState(x+"_"+y, "black");
}else if (AllDef.WHITE == PlayerWhite.getChess(x, y)){
setState.setUiState(x+"_"+y, "white");
}
}
}
}
//显示黑白棋有效棋子数目
public static void check(){
WidgetUtil.setText("txtWhite", "白棋:"+PlayerWhite.getNum());
WidgetUtil.setText("txtBlack", " 黑棋:"+Player.getNum());
int ws=PlayerWhite.getNum();
int bs=Player.getNum();
String winner="";
//等待白棋走下一步
if(AllDef.NOSET == Player.result())
{
Game.m_turn = AllDef.WHITE;
next(1,1);
}
//等待黑棋走下一步
if(AllDef.NOSET == PlayerWhite.result())
{
Game.m_turn = AllDef.BLACK;
}
//黑棋获胜
if(AllDef.WIN == Player.result())
{
Api.info("WIN");
Player.initChessBoard();
PlayerWhite.initChessBoard();
setState.showScreen();
//显示获胜页面
resultPage(ws,bs,"BLACK");
}
//白棋获胜
else if(AllDef.WIN == PlayerWhite.result())
{
Api.info(" PlayerWhite WIN");
Player.initChessBoard();
PlayerWhite.initChessBoard();
setState.showScreen();
//显示获胜页面
resultPage(ws,bs,"WHITE");
}
if(PlayerWhite.getNum()+Player.getNum() == 64)
{
if(PlayerWhite.getNum() > Player.getNum())
{
Api.info(" White WIN");
WidgetUtil.setText("txtMsg", "白棋获胜,得分是 "+PlayerWhite.getNum());
winner="WHITE";
}
else if(PlayerWhite.getNum() < Player.getNum())
{
WidgetUtil.setText("txtMsg", "黑棋获胜 ,得分是 "+Player.getNum());
winner="BLACK";
}
else
{
WidgetUtil.setText("txtMsg", "平局 !");
}
Player.initChessBoard();
PlayerWhite.initChessBoard();
setState.showScreen();
resultPage(ws,bs,winner);
}
}
}
d.日志Api.info自己打印:
public static void info(Object message){
if(message ==null){
Api.info("--info-->???");
}else{
Api.info("--info-->"+message);
}
Api.debug("--debug-->"+message);
Api.error("--error-->"+message);
}
2) xml页面
(1)在xml页面中使用<picture></picture>组件替换J2ME中的Image组件。<container></container>组件替换J2ME中的Graphics组件。
(2)MyGameCanvas.java;类不再需要了,页面布局通过xml和CSS文件就可以实现。
(3)最重要的,你根本不用管原生J2ME代码是如何写的,你也不需要懂java语言。你只要根据原生代码运行出的显示效果自己写xml页面就可以了,这就是UDE的强势之处。你甚至可以在不同的手机上运行原生代码,选择一个看起来非常漂亮的显示效果模仿开发,页面还原相似度可以达到90%以上。唯一差异的是,UDE开发的界面效果只有一套,不能像原生开发一样,一款手机一套显示效果。
e.与Android、Windows Phone 7一样,UDE采用XML作为界面设计的载体,符合当前的技术发展趋势,降低开发者的学习成本。
统一开发环境UDE下载
【示例代码】利用UDE开发黑白棋游戏(一)
【示例代码】利用UDE开发黑白棋游戏(二)