如何使用J2ME中的线程

线程在J2ME开发中是不可或缺的一部分,J2ME继承了J2SE中关于java.lang中的Runnable接口,以及Thread类。但是,由于J2ME应用的特殊性,J2ME程序中去除了部分API,没有线程组的概念,也没有daemon线程。

今天,我们从一个例子出发,来学习J2ME当中的线程的概念。我们选取的例子是俄罗斯方块。首先,有一些要注意的事项:

1.注意一点,要注意在J2me中不要使用浮点数,这样可以通过编译,但是不能通过预验证。因为一般手持设备都无法负担浮点运算的高负荷。

2.在J2ME程序当中,绝大多数的空间为图片所占有,我们可以看到,今天我们的例子没有任何图片,仅仅5k,如果是开发产品,不可避免的要使用图片,

但是尽量使用压缩率高的png图片,而且不要太过复杂,因为复杂的图片会使得图片变得很大。

3.在程序中尽量使用常量特别是位置信息,这样当作修改的时候只要改一个量就可以了,而且当移植到其他平台的时候也会减少很多工作量.还有就是颜色

信息等.不用每次记忆,重新构造,因为J2me中的颜色和j2se的不太一样.没有常量定义.

4.游戏产品经常需要保护版权,而当今的很多反编译工具可以轻而易举地把jar文件的内容反编译过来,因此可以对程序进行模糊化处理,使得无法反编译

或者反编译后无法理解.可以右键点击项目,在属性中选择Build|Obfuscating,选择模糊化级别.

5.讲解中我们都使用NetBeans作为开发平台,有关安装事宜请访问www.netbeans.org.

好,我们开始吧。

A. 首先,建立一个新的移动应用程序项目,取名Tetris, 不要自动创建Hello程序,选取MIDP1.0和CLDC1.0.

B. 新建一个包,方法是右键点击项目,选取New|Java Package,取名Tetris.

C. 新建一个Midlet,同上,选取New|Java Midlet, 取名TetrisMidlet.

D. 我们需要一个能够显示游戏的Canvas, 因此新建一个Class名叫TetrisCanvas, 在TetrisMidlet.java中将TetrisCanvas作为当前可以显示的元素:

现在的TetrisMidlet.java如下:

package Tetris;import javax.microedition.midlet.*;import javax.microedition.lcdui.*;/**** @author lin* @version*/public class TetrisMidlet extends MIDlet {public void startApp() {Display display = Display.getDisplay( this );// TetrisCanvas extends Canvas which extends Displayable so it can// be displayed directlydisplay.setCurrent( new TetrisCanvas());}public void pauseApp() {}public void destroyApp(boolean unconditional) {}}

由于TetrisCanvas继承了Canvas,所以可以被TetrisMidlet所显示.

E. 这里,我们需要将TetrisCanvas继承Canvas,并且实现Canvas的接口函数paint(),我们现在有了一个TetrisCanvas的框架了。

package Tetris;import javax.microedition.lcdui.*;public class TetrisCanvas extends Canvas {/** Creates a new instance of TetrisCanvas */public TetrisCanvas() {}protected void paint(Graphics g){}}

下面我们需要使得TetrisCanvas具有Thread的特性,这里有两种方法,一种是让TetrisCanvas继承Thread类,然后生成它的实例,但是由于它已经

继承了Canvas类,而Java中不允许多重继承,因此,我们在编程当中通常采取第二种做法,也就是让它实现Runnable接口,在成员中声明一个Thread

成员,实例生成指向自己,然后实现run方法。

也就是这样:

public class TetrisCanvas extends Canvas implements Runnable {private Thread Blocker = null;...public TetrisCanvas(){Blocker = new Thread(this);Blocker.start();}...public void run(){while (Blocker != null) {}}...}

F. 程序逻辑:下面给出程序清单。程序中我们使用一个数组来存储方块的信息,一共有十九种,还有一个数组来存储当前的画面方格的内容.在程序中

有一个paint方法来实现重画,注意绘制的先后次序,当程序规模变得很大的时候,重画的效率就非常重要,需要进行优化.我们在程序中使用了背景,

在没有背景的情况下,程序仅5k,采用背景后,程序47k,可见对图片的优化至关重要.

/** TetrisCanvas.java** Created on 2005年7月13日, 上午11:31** To change this template, choose Tools | Options and locate the template under* the Source Creation and Management node. Right-click the template and choose* Open. You can then make changes to the template in the Source Editor.*/package Tetris;import java.util.*;import java.lang.Math;import javax.microedition.lcdui.*;/**** @author lin*/public class TetrisCanvas extends Canvas implements Runnable{private Thread Blocker = null;private Random generator;private int FutureBlockType, BlockType,LastType,LastX,LastY,BlockX,BlockY ;private int BlockLines,BlockScore;private int BlockSpeed,CurSpeed;private static final int COLOR_GRAY = 0x00eeeeee;private static final int COLOR_RED = 0x00ff0000;private static final int COLOR_BLACK = 0x00000000;private static final int COLOR_WHITE = 0x00ffffff;private static final int COLOR_BLUE = 0x000000ff;private static final int COLOR_LIGHT_BLUE= 0x0089a5d1;private static final int COLOR_DARK_GRAY = 0x00808080;private static final int COLOR_BACKGROUND= COLOR_LIGHT_BLUE;private static final int BLOCK_SIZE = 7;private static final int CANVAS_SIZE_WIDTH = 12;private static final int CANVAS_SIZE_HEIGHT = 22;private static final int CANVAS_OFFSET_X = 5;private static final int CANVAS_OFFSET_Y = 7;/*** The paint status.*/boolean ISCLEAR = false;boolean ISDOWN = false;boolean ISDEL = false;/*** the block information matrix.*/int BlockInfo[][]={{1,0,1,1,1,2,1,3,0xff0000,2},{0,1,1,1,2,1,3,1,0xff0000,4},{0,0,0,1,1,1,1,2,0x0000ff,2},{0,1,1,0,1,1,2,0,0x0000ff,3},{0,1,0,2,1,0,1,1,0x00ff00,2},{0,0,1,0,1,1,2,1,0x00ff00,3},{0,0,0,1,1,0,1,1,0xffff00,2},{0,1,1,0,1,1,1,2,0x00ffff,2},{0,1,1,0,1,1,2,1,0x00ffff,3},{1,0,1,1,1,2,2,1,0x00ffff,3},{0,1,1,1,1,2,2,1,0x00ffff,3},{0,1,0,2,1,1,2,1,0xff00ff,3},{0,0,1,0,1,1,1,2,0xff00ff,3},{0,1,1,1,2,0,2,1,0xff00ff,3},{1,0,1,1,1,2,2,2,0xff00ff,3},{0,0,0,1,1,1,2,1,0xffffff,3},{1,0,1,1,1,2,2,0,0xffffff,3},{0,1,1,1,2,1,2,2,0xffffff,3},{0,2,1,0,1,1,1,2,0xffffff,3},};// Gridmatrix 中只存储颜色信息int Gridmatrix[][]=new int[CANVAS_SIZE_HEIGHT][CANVAS_SIZE_WIDTH];/*** Initialize the applet. Resize and load images.*/public void init() {BlockType=Math.abs(generator.nextInt()%19);FutureBlockType=Math.abs(generator.nextInt()%19);LastType=BlockType;BlockLines=0;BlockScore=0;BlockSpeed=1;CurSpeed=BlockSpeed;BlockX=4; LastX=BlockX;BlockY=0; LastY=BlockY;//初始化Gridmatrix矩阵,内容为带边框的主绘图区。for(int i=0;ifor(int j=0;jGridmatrix[i][j]=0;for(int i=0;iGridmatrix[CANVAS_SIZE_HEIGHT-1][i]=COLOR_DARK_GRAY;for(int i=0;iGridmatrix[i][0]=COLOR_DARK_GRAY;Gridmatrix[i][11]=COLOR_DARK_GRAY;}}/** Creates a new instance of TetrisCanvas */public TetrisCanvas() {generator = new Random( System.currentTimeMillis() );init();Blocker = new Thread(this);Blocker.start();}private void draw3DBlock(Graphics g, int c, int x, int y, int width, int height){int color = g.getColor();g.setColor( COLOR_WHITE );g.drawRect( x, y, width, height );g.setColor(c);g.fillRect( x + 1, y + 1, width-2, height-2 );g.setColor( COLOR_BLACK );g.drawLine( x + width-1, y, x + width-1, y + height-1 );g.drawLine( x, y + height-1, x + width-1, y + height-1 );g.setColor(color);}public static boolean drawText(Graphics g, String str, int x, int y, int anchor, int color, int size) {Font f_old,f_new;int c_old;try {f_old = g.getFont();f_new = Font.getFont(Font.FACE_SYSTEM,Font.STYLE_BOLD,size);g.setFont(f_new);c_old = g.getColor();g.setColor(color);g.drawString(str, x, y, anchor );g.setColor(c_old);g.setFont(f_old);return true;}catch (Exception ex) {return false;}}protected void paint(Graphics g){//画背景try{Image image_Splash = Image.createImage("/back.png");g.drawImage(image_Splash, 0, 0,Graphics.TOP | Graphics.LEFT);}catch(Exception ex) {}//画下一个要出现的方块drawText(g, "下一个", 91, 5, Graphics.TOP| Graphics.LEFT, COLOR_BLUE, Font.SIZE_SMALL);g.setColor(COLOR_GRAY);g.drawRoundRect(91, 18, 26, 30, 2, 2);g.setColor(COLOR_DARK_GRAY);g.fillRoundRect(92, 19, 24, 28, 2, 2);for(int i=0;i<=3;i++)draw3DBlock(g, BlockInfo[FutureBlockType][8],93+BlockInfo[FutureBlockType][i*2+1]*BLOCK_SIZE,20+BlockInfo[FutureBlockType][i*2]*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE);drawText(g, "速度:"+String.valueOf(CurSpeed), 91, 60, Graphics.TOP| Graphics.LEFT, COLOR_BLUE, Font.SIZE_SMALL);drawText(g, "行数:"+String.valueOf(BlockLines), 91, 75, Graphics.TOP| Graphics.LEFT, COLOR_BLUE, Font.SIZE_SMALL);drawText(g, "成绩:", 91, 90, Graphics.TOP| Graphics.LEFT, COLOR_BLUE, Font.SIZE_SMALL);g.setColor(COLOR_GRAY);g.drawRoundRect(91, 105, 26, 20, 2, 2);g.setColor(COLOR_DARK_GRAY);g.fillRoundRect(92, 106, 24, 18, 2, 2);drawText(g, String.valueOf(BlockScore), 93, 107, Graphics.TOP| Graphics.LEFT, COLOR_WHITE, Font.SIZE_MEDIUM);//画当前战况for(int i=0;ifor(int j=1;jif (Gridmatrix[i][j]!=0)draw3DBlock(g,Gridmatrix[i][j],CANVAS_OFFSET_X+j*BLOCK_SIZE,CANVAS_OFFSET_Y+i*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE);if (!ISDOWN){//画上新的方块LastX=BlockX; LastY=BlockY; LastType=BlockType;for(int i=0;i<=3;i++)draw3DBlock(g,BlockInfo[BlockType][8],CANVAS_OFFSET_X+BlockX*BLOCK_SIZE+BlockInfo[BlockType][i*2+1]*BLOCK_SIZE,CANVAS_OFFSET_Y+BlockY*BLOCK_SIZE+BlockInfo[BlockType][i*2]*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE);}}private boolean feasible(){for(int i=0;i<=3;i++)if (Gridmatrix[BlockY+BlockInfo[BlockType][i*2]][BlockX+BlockInfo[BlockType][i*2+1]]!=0)return false;return true;}private void delline(){for(int i=0;i0)&&(i>=1)){CanSkip=false;label1: for(int j=1;j=1;k--)for(int l=1;l<=CANVAS_SIZE_WIDTH-2;l++)Gridmatrix[k][l]=Gridmatrix[k-1][l];BlockLines++;BlockScore+=200;if((BlockScore%2000)<200) CurSpeed++;}}}public void run() {while (Blocker != null) {if(!ISDOWN){BlockY++;if (!feasible()) {ISDOWN=true; BlockY--; delline();try {Thread.sleep(400);} catch (InterruptedException e){}}else{repaint();try {Thread.sleep(950-100*(int)BlockSpeed);} catch (InterruptedException e){}}}else{ BlockScore+=50;if((BlockScore%2000)<50) CurSpeed++;ISDOWN=false;repaint();BlockSpeed=CurSpeed;BlockType=FutureBlockType;FutureBlockType=Math.abs(generator.nextInt()%19);BlockX=4; LastX=BlockX;BlockY=0; LastY=BlockY;if (!feasible()) { init();}}}Blocker = null;}protected void keyPressed(int keyCode) {//处理按下键盘的事件,这是Canvas的实例方法switch (getGameAction(keyCode)) {//将按键的值转化成方向常量case Canvas.UP://向上break;case Canvas.DOWN://向下BlockY++;if (!feasible()) BlockY--;repaint();BlockSpeed=9;//Blocker.run();break;case Canvas.LEFT://向左BlockX--;if (!feasible()) BlockX++;break;case Canvas.RIGHT://向右BlockX++;if (!feasible()) BlockX--;break;case Canvas.FIRE:int tempBlockType=BlockType;if (BlockType==1) BlockType=-1;else if (BlockType==3) BlockType=1;else if (BlockType==5) BlockType=3;else if (BlockType==6) BlockType=5;else if (BlockType==10) BlockType=6;else if (BlockType==14) BlockType=10;else if (BlockType==18) BlockType=14;BlockType++;if (!feasible()) BlockType=tempBlockType;break;default:break;}repaint(); return;}}

参考

J2MEWTK 2.2 documentation.

天不负;卧薪尝胆,三千越甲可吞吴。

如何使用J2ME中的线程

相关文章:

你感兴趣的文章:

标签云: