【贪吃蛇—Java程序员写Android游戏】系列 3. 用J2ME实现Android的Snake Sample详解

 

本次会详细讲解将Android的Snake Sample移植到J2ME上,从而比较二者的区别和联系。

在《1.Android SDK Sample-Snake详解》中,我们已经详细介绍了Android实现的Snake项目结构,现在我们要将这个项目用J2ME实现。

一、 J2ME vs. Android

Android的UI实用、方便,而且很美观,基本无需改动且定制方便。而J2ME的高级用户界面比较鸡肋,在现在大多数的应用里都看不到,多数稍微复杂点的界面都是手工画,或是用一些开源的高级UI库。接下来我们简单比较下二者的区别,为Snake项目从Android到J2ME的移植做准备。

1. 平台

J2ME

开发平台

Android

操作系统

2. 工程结构

J2ME

res:资源文件

src:源代码

Android

src:源代码

res\drawable:图片

res\raw:声音

res\values:字符串

assets:数据文件

3. 安装包

J2ME

jad,jar

Android

apk

4. 代码结构

J2ME

MIDlet,Canvas,采用继承的方式,只有一个MIDlet,一般只有一个Canvas

Android

Activity,View,采用继承的方式,只有一个Activity,一般只有一个View

5. 入口程序

J2ME

MIDlet类

Android

Activity类

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 {

// TODO Auto-generated method stub

}

protected void pauseApp() {

// TODO Auto-generated method stub

}

protected void startApp() throws MIDletStateChangeException {

// TODO Auto-generated method stub

}

}

Android

package com.deaboway.android;

import android.app.Activity;

import android.os.Bundle;

public class myActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

}

}

7. 生命周期-开始

J2ME

startApp(),活动状态,启动时调用,初始化。

Android

onCreate(),返回时也会调用此方法。

onCreate()后调用onStart(),onStart()后调用onResume(),此时Activity进入运行状态。

8. 生命周期-暂停

J2ME

pauseApp(),暂停状态,如来电时,调用该接口。

Android

onPause()。

9. 生命周期-销毁

J2ME

destroyApp(),销毁状态,退出时调用。

Android

onStop(),程序不可见时调用onDestroy(),程序销毁时调用。

10. 刷新

J2ME

高级UI组件由内部刷新实现。低级UI,canvas中通过调用线程结合repaint()来刷新,让线程不断循环。低级UI架构可以用MVC方式来实现,建议使用二级缓存。

Android

高级UIHandler类通过消息的机制刷新。onDraw()刷新接口,低级UI开发者用线程控制更新,在lockCanvas()和unlockCanvasAndPost()方法之间绘制。

如果去读API,我们可以发现J2ME中Canvas的repaint()与Android中View的invalidate()/postInvalidate()方法实现了相同的功能(连说明文字几乎都一样…),但是invalidate()/postInvalidate()两者却有着区别:invalidate() 只能在UI这个线程里通过调用onDraw(Canvas canvas)来update屏幕显示,而postInvalidate()是要在non-UI线程里做同样的事情的。这就要求我们做判断,哪个调用是本 线程的,哪个不是,这在做多线程callback的时候尤为重要。而在J2ME中,不管怎样直接调用repaint()就好了。

11. 绘画

J2ME

Displayable类。J2me中所有可显示的组件都是直接或间接的继承了Displayable,直接的是Canvas和Screen。不同的继承导致了低级 UI和高级UI的区别。J2me中现成的UI组件都是直接或者间接继承了Screen。只要调用Display.getDisplay(MIDLet instan).setCurrrent(Displayable disp),就可以把组件显示到手机界面上。切换界面的时候也可以使用该接口。

Android

View类。可见的组件直接或者间接继承了android.view.View。通过 Activity.setContentView(View view)就可以显示在android手机界面上,切换界面的时候也可以使用该接口。如果是直接继承了View而不是Android自带的UI组件,那么 还要自己去实现它的刷新,类似J2me的低级UI组件。

12. 画笔

J2ME

高级UI组件由内部刷新实现。低级UI,canvas中通过调用线程结合repaint()来刷新,让线程不断循环。低级UI架构可以用MVC方式来实现,建议使用二级缓存。

Android

Canvas类,Android绘 制的时候会传入一个参数Paint。该对象表示绘制的风格,比如颜色,字体大小,字体格式等。Android的Canvas不同于J2ME的Canvas,它更像于J2ME的Graphics,用来绘制。

13. 全屏

J2ME

Canvas中SetFullScreenMode()。

Android

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);requestWindowFeature(Window.FEATURE_NO_TITLE);

14. 获得屏幕尺寸

J2ME

Canvas类的getHeight()和getWidth()

Android

Display d = getWindowManager().getDefaultDisplay();

screenWidth = d.getWidth();

screenHeight = d.getHeight();

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);//释放当前状态

Android

canvas.save();//保存当前状态

canvas.clipRect(x,y, x+width, y+height)

cavnas.resave();//释放当前状态

16. 清屏操作

J2ME

g.setColor(Color.WHITE);

g.fillRect(0,0,getWidth(),getHeight());

Android

// 首先定义paint

Paint paint = new Paint();

// 绘制矩形区域-实心矩形

// 设置颜色

paint.setColor(Color.WHITE);

// 设置样式-填充

paint.setStyle(Style.FILL);

// 绘制一个矩形

canvas.drawRect(new Rect(0, 0, getWidth(), getHeight()), paint);

17. 双缓冲

J2ME

Image bufImage=Image.createImage(bufWidth, bufHeight);

Graphics bufGraphics=bufImage.getGraphics();

Android

Bitmap carBuffer = Bitmap.createBitmap(bufWidth, bufHeight, Bitmap.Config.ARGB_4444); 

Canvas carGp = new Canvas(carBuffer);

18. 图片类

J2ME

Image类,Image.createImage(path);

Android

BitMap类,BitmapFactory.decodeResource(getResources(),R.drawable.map0);

19. 绘制矩形

J2ME

drawRect的后两个参数为宽度和高度

Android

drawRect的后两个参数为结束点的坐标

20. 按键

J2ME

keyPressed()

keyRepeated()

keyReleased()

Android

onKeyDown()

onKeyUp()

onTracKballEvent()

21. 键值

J2ME

Canvas.LEFT…

Android

KeyEvent.KEYCODE_DPAD_LEFT…

22. 触笔

J2ME

pointerPressed(),pointerReleased(),pointerDragged()

Android

onTouchEvent()

23. 数据存储

J2ME

Record Management System (RMS)

Android

SQLite数据库,SharedPreferences类

24. 连接

J2ME

从Connector打开,可以直接在Connector.Open时设置连接是否可读写,以及超时设置

Android

从URL对象打开,必须使用setDoInput(boolean)和setDoOutput(boolean)方法设置,使用setConnectTimeout(int)不仅可以对连接超时进行设置,还能设置超时时间,参数为0时忽略连接超时

25. 游戏开发包

J2ME

javax.microedition.lcdui.game.*;

GameCanvas/Layer/LayerManager/ Sprite/TiledLayer

Android

无专门针对游戏的开发包。

26. 音效

J2ME

Player s=Manager.createPlayer(InputStream);

s.prepare();//创建

s.start();//播放

s.stop();//暂停

s.stop();//关闭

s.release();//释放

Android

MediaPlayer类处理背景音乐

SoundPool类处理一些简单的音效

27. 显示文本

J2ME

String

Android

TextView类

28. 打印信息

J2ME

System.out.println()

Android

Log类

二、 迁移关键点

1. 基础类和结构

J2ME程序的主体从Activity改变为MIDlet,TileView从View改变为Canvas,相关的方法也需要进行调整,但是主体结构和逻辑还是一致的。此外,有些J2ME不支持的类,需要做对应处理。

资源获取,从xml改为自行获取:

 1  private   void  initSnakeView() {
 2 
 3  //  获取图片资源
 4 
 5  try  {
 6 
 7  imageRED_STAR  =  Image.createImage( " /redstar.png " );
 8 
 9  imageRED_STAR  =  Utils.zoomImage(imageRED_STAR,mTileSize,mTileSize);
10 
11  imageYELLOW_STAR  =  Image.createImage( " /yellowstar.png " );
12 
13  imageYELLOW_STAR  =  Utils.zoomImage(imageYELLOW_STAR,mTileSize,mTileSize);
14 
15  imageGREEN_STAR  =  Image.createImage( " /greenstar.png " );
16 
17  imageGREEN_STAR  =  Utils.zoomImage(imageGREEN_STAR,mTileSize,mTileSize);
18 
19  catch (Exception e) {
20 
21  Log.info( " Create Images:  " + e);
22 
23  }
24 
25  //  设置贴片图片数组
26 
27  resetTiles( 4 );
28 
29  //  把三种图片存到Bitmap对象数组
30 
31  loadTile(RED_STAR, imageRED_STAR);
32 
33  loadTile(YELLOW_STAR, imageYELLOW_STAR);
34 
35  loadTile(GREEN_STAR, imageGREEN_STAR);
36 
37  }

 

ArrayList,用Vector替换掉:

 

 1  //  坐标数组转整数数组,把Coordinate对象的x y放到一个int数组中——用来保存状态
 2 
 3  private  String coordVectorToString(Vector cvec) {
 4 
 5  int  count  =  cvec.size();
 6 
 7  StringBuffer rawArray  =   new  StringBuffer();
 8 
 9  for  ( int  index  =   0 ; index  <  count; index ++ ) {
10 
11  Coordinate c  =  (Coordinate) cvec.elementAt(index);
12 
13  rawArray.append(c.x + " , " );
14 
15  rawArray.append(c.y + " , " );
16 
17  Log.info( " coordVectorToString(), c.x= " + c.x + " ,c.y= " + c.y);
18 
19  }
20 
21  Log.info( " coordVectorToString(), rawArray.toString= " + rawArray);
22 
23  return  rawArray.toString();
24 
25  }
26 
27  //  整数数组转坐标数组,把一个int数组中的x y放到Coordinate对象数组中——用来恢复状态
28 
29  //  @J2ME 还是用Vector替换ArrayList
30 
31  private  Vector coordStringToVector(String raw) {
32 
33  Vector coordArrayList  =   new  Vector();
34 
35  Log.info( " coordStringToVector(), raw= " + raw);
36 
37  String[] rawArray  =  Utils.splitUtil(raw, " , " );
38 
39  Log.info( " coordStringToVector(), rawArray.length= " + rawArray.length);
40 
41  int  coordCount  =  rawArray.length;
42 
43  for  ( int  index  =   0 ; index  <  coordCount; index  +=   2 ) {
44 
45  Coordinate c  =   new  Coordinate(Integer.parseInt(rawArray[index]), Integer.parseInt(rawArray[index  +   1 ]));
46 
47  coordArrayList.addElement(c);
48 
49  }
50 
51  return  coordArrayList;
52 
53  }

 

 

Bundle,用RMS实现:

 

  1  /**
  2 
  3  * <p>Title: Snake</p>
  4 
  5  * <p>Copyright: (C) 2011 Gavin's Snake project. Licensed under the Apache License, Version 2.0 (the "License")</p>
  6 
  7  @author  Gavin
  8 
  9  */
 10 
 11  package  com.deaboway.snake.util;
 12 
 13  import  java.io.ByteArrayInputStream;
 14 
 15  import  java.io.ByteArrayOutputStream;
 16 
 17  import  java.io.DataInputStream;
 18 
 19  import  java.io.DataOutputStream;
 20 
 21  import  javax.microedition.rms.RecordStore;
 22 
 23  public   class  Bundle  extends  BaseRMS {
 24 
 25  private   static  String[] SECTION  =  {
 26 
 27  " \"AL\": " , " \"DT\": " ,
 28 
 29  " \"ND\": " , " \"MD\": " ,
 30 
 31  " \"SC\": " , " \"ST\": " };
 32 
 33  private   static   int  LEN  =  SECTION.length;
 34 
 35  private   static   boolean  inited  =   false ;
 36 
 37  private   static  Bundle INSTANCE;
 38 
 39  public   static   void  INIT(){
 40 
 41  if (inited) return ;
 42 
 43  inited  =   true ;
 44 
 45  INSTANCE  =   new  Bundle();
 46 
 47  INSTANCE.loadBundles();
 48 
 49  }
 50 
 51  public   static  Bundle getInstance(){
 52 
 53  return  INSTANCE;
 54 
 55  }
 56 
 57  private  String[] CONTENT  =   new  String[LEN];
 58 
 59  private  Bundle() {
 60 
 61  super ( " snake-view " );
 62 
 63  }
 64 
 65  public   void  loadBundles() {
 66 
 67  try  {
 68 
 69  this .open();
 70 
 71  this .close();
 72 
 73  catch  (Exception e) {
 74 
 75  try  {
 76 
 77  this .close();
 78 
 79  RecordStore.deleteRecordStore( this .getRMSName());
 80 
 81  this .open();
 82 
 83  this .close();
 84 
 85  catch  (Exception ex) {
 86 
 87  }
 88 
 89  }
 90 
 91  }
 92 
 93  public   void  resetBundles() {
 94 
 95  try  {
 96 
 97  this .close();
 98 
 99  RecordStore.deleteRecordStore( this .getRMSName());
100 
101  this .open();
102 
103  this .close();
104 
105  catch  (Exception ex) {
106 
107  }
108 
109  }
110 
111  public   void  updateBundles()  throws  Exception {
112 
113  try  {
114 
115  this .openonly();
116 
117  updateData();
118 
119  if  ( this .getRecordStore()  !=   null )
120 
121  this .close();
122 
123  catch  (Exception e) {
124 
125  throw   new  Exception( this .getRMSName()  +   " ::updateBundles:: "   +  e);
126 
127  }
128 
129  }
130 
131  protected   void  loadData()  throws  Exception {
132 
133  try  {
134 
135  byte [] record  =   this .getRecordStore().getRecord( 1 );
136 
137  DataInputStream istream  =   new  DataInputStream(
138 
139  new  ByteArrayInputStream(record,  0 , record.length));
140 
141  String content  =  istream.readUTF();
142 
143  int [] start  =   new   int [LEN + 1 ];
144 
145  for ( int  i  = 0 ;i < LEN;i ++ ){
146 
147  start[i]  =  content.indexOf(SECTION[i]);
148 
149  }
150 
151  start[LEN] = content.length();
152 
153  for ( int  i  = 0 ;i < LEN;i ++ ){
154 
155  CONTENT[i]  =  content.substring(start[i] + 5 ,start[i + 1 ]);
156 
157  Log.info( " CONTENT[ " + i + " ]= " + CONTENT[i]);
158 
159  }
160 
161  catch  (Exception e) {
162 
163  throw   new  Exception( this .getRMSName()  +   " ::loadData:: "   +  e);
164 
165  }
166 
167  }
168 
169  protected   void  createDefaultData()  throws  Exception {
170 
171  try  {
172 
173  ByteArrayOutputStream bstream  =   new  ByteArrayOutputStream( 12 );
174 
175  DataOutputStream ostream  =   new  DataOutputStream(bstream);
176 
177  CONTENT[ 0 =   " 9,20,9,7 " ;
178 
179  CONTENT[ 1 =   " 1 " ;
180 
181  CONTENT[ 2 =   " 1 " ;
182 
183  CONTENT[ 3 =   " 600 " ;
184 
185  CONTENT[ 4 =   " 0 " ;
186 
187  CONTENT[ 5 =   " 7,7,6,7,5,7,4,7,3,7,2,7 " ;
188 
189  StringBuffer sb  =   new  StringBuffer();
190 
191  for ( int  i = 0 ;i < LEN;i ++ ){
192 
193  sb.append(SECTION[i]);
194 
195  sb.append(CONTENT[i]);
196 
197  }
198 
199  ostream.writeUTF( sb.toString());
200 
201  ostream.flush();
202 
203  ostream.close();
204 
205  byte [] record  =  bstream.toByteArray();
206 
207  this .getRecordStore().addRecord(record,  0 , record.length);
208 
209  catch  (Exception e) {
210 
211  throw   new  Exception( this .getRMSName()  +   " ::createDefaultData:: "   +  e);
212 
213  }
214 
215  }
216 
217  protected   void  updateData()  throws  Exception {
218 
219  try  {
220 
221  ByteArrayOutputStream bstream  =   new  ByteArrayOutputStream( 12 );
222 
223  DataOutputStream ostream  =   new  DataOutputStream(bstream);
224 
225  StringBuffer sb  =   new  StringBuffer();
226 
227  for ( int  i = 0 ;i < LEN;i ++ ){
228 
229  sb.append(SECTION[i]);
230 
231  sb.append(CONTENT[i]);
232 
233  }
234 
235  ostream.writeUTF(sb.toString());
236 
237  ostream.flush();
238 
239  ostream.close();
240 
241  byte [] record  =  bstream.toByteArray();
242 
243  this .getRecordStore().setRecord( 1 , record,  0 , record.length);
244 
245  catch  (Exception e) {
246 
247  throw   new  Exception( this .getRMSName()  +   " ::updateData:: "   +  e);
248 
249  }
250 
251  }
252 
253  public  String getValue( int  key) {
254 
255  return  CONTENT[key];
256 
257  }
258 
259  public   void  setValue( int  key, String value) {
260 
261  CONTENT[key]  =  value;
262 
263  }
264 
265  }

 

 

Log,自己实现Log系统:

 

 1  /**
 2 
 3  * <p>Title: Snake</p>
 4 
 5  * <p>Copyright: (C) 2011 Gavin's Snake project. Licensed under the Apache License, Version 2.0 (the "License")</p>
 6 
 7  @author  Gavin
 8 
 9  */
10 
11  package  com.deaboway.snake.util;
12 
13  public   class  Log{
14 
15  private   static   final   int  FATAL  =   0 ;
16 
17  private   static   final   int  ERROR  =   1 ;
18 
19  private   static   final   int  WARN  =   2 ;
20 
21  private   static   final   int  INFO  =   3 ;
22 
23  private   static   final   int  DEBUG  =   4 ;
24 
25  private   static   int  LOG_LEVEL  =  INFO;
26 
27  public   static   void  info(String string){
28 
29  if (LOG_LEVEL  >=  INFO){
30 
31  System.out.println( " [Deaboway][ INFO]  "   +  string);
32 
33  }
34 
35  }
36 
37  public   static   void  debug(String string){
38 
39  if (LOG_LEVEL  >=  DEBUG){
40 
41  System.out.println( " [Deaboway][DEBUG]  "   +  string);
42 
43  }
44 
45  }
46 
47  public   static   void  warn(String string){
48 
49  if (LOG_LEVEL  >=  WARN){
50 
51  System.out.println( " [Deaboway][ WARN]  "   +  string);
52 
53  }
54 
55  }
56 
57  public   static   void  error(String string){
58 
59  if (LOG_LEVEL  >=  ERROR){
60 
61  System.out.println( " [Deaboway][ERROR]  "   +  string);
62 
63  }
64 
65  }
66 
67  public   static   void  fatal(String string){
68 
69  if (LOG_LEVEL  >=  FATAL){
70 
71  System.out.println( " [Deaboway][FATAL]  "   +  string);
72 
73  }
74 
75  }
76 
77  }

 

 

2. TileView

(1)用Image替换BitMap,“private Image[] mTileArray;”

(2)private final Paint mPaint = new Paint();不再需要了。直接在Graphics中drawImage即可

(3)onSizeChanged() 不会被自动调用,需要在构造函数中主动调用,以实现对应功能。onSizeChanged(this.getWidth(),this.getHeight());

(4)最重要的,用paint替换onDraw,呵呵,Canvas的核心啊!失去它你伤不起!!!咱也试试咆哮体!!!!!!

3. SnakeView

(1)J2ME 没有Handler,直接用Thread定期repaint()就OK。这里要啰嗦几句。

熟悉Windows编程的朋友可能知道Windows程序是消息驱动的,并且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制。实际上Android中也实现了类似Windows的消息循环机制,它通过Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。

Android系统中Looper负责管理线程的消息队列和消息循环。Handler的作用是把消息加入特定的(Looper)消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。

一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了。因为主线程一般负责界面的更新操作,并且Android系统中的weget不是线程安全的,所以这种方式可以很好的实现Android界面更新。在Android系统中这种方式有着广泛的运用。

如果另外一个线程要把消息放入主线程的消息队列,就需要通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列。并且将会在Handler主线程中调用该handler的handleMessage接口来处理消息。

之所以Android有这些处理,是因为Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新。而对于J2ME来说,Thread比较简单,直接匿名创建重写run方法,调用start方法执行即可。或者,也可以从Runnable接口继承。实现如下:

 1  class  RefreshHandler  extends  Thread {
 2 
 3  public   void  run() {
 4 
 5  while  ( true ) {
 6 
 7  try  {
 8 
 9  // delay一个延迟时间单位
10 
11  Thread.sleep(mMoveDelay);
12 
13  catch  (Exception e) {
14 
15  e.printStackTrace();
16 
17  }
18 
19  //  更新View对象
20 
21  SnakeView. this .update();
22 
23  //  强制重绘
24 
25  SnakeView. this .repaint();
26 
27  }
28 
29  }
30 
31  };

 

 

(2)直接使用String代替TextView类,在Canvas的paint()中直接绘制各种提示信息。

(3)在一些地方需要主动调用repaint()进行强制重绘。

其它具体参考源代码。

4. Snake

本类就比较简单了,直接把源代码贴出来如下:

 

  1  /**
  2 
  3  * <p>Title: Snake</p>
  4 
  5  * <p>Copyright: (C) 2011 Gavin's Snake project. Licensed under the Apache License, Version 2.0 (the "License")</p>
  6 
  7  @author  Gavin
  8 
  9  */
 10 
 11  package  com.deaboway.snake;
 12 
 13  import  javax.microedition.lcdui.Display;
 14 
 15  import  javax.microedition.midlet.MIDlet;
 16 
 17  import  javax.microedition.midlet.MIDletStateChangeException;
 18 
 19  import  com.deaboway.snake.util.BaseRMS;
 20 
 21  import  com.deaboway.snake.util.Bundle;
 22 
 23  import  com.deaboway.snake.util.Log;
 24 
 25  /**
 26 
 27  * Snake: a simple game that everyone can enjoy.
 28 
 29  *
 30 
 31  * 贪吃蛇: 经典游戏,在一个花园中找苹果吃,吃了苹果会变长,速度变快。碰到自己和墙就挂掉
 32 
 33  *
 34 
 35  */
 36 
 37  public   class  Snake  extends  MIDlet {
 38 
 39  public   static  Display display;
 40 
 41  public   static  SnakeView mSnakeView;
 42 
 43  public   static  MIDlet SNAKE;
 44 
 45  public  Snake() {
 46 
 47  Bundle.INIT();
 48 
 49  display = Display.getDisplay( this );
 50 
 51  SNAKE  =   this ;
 52 
 53  mSnakeView  =   new  SnakeView();
 54 
 55  mSnakeView.setTextView( "" );
 56 
 57  mSnakeView.setMode(SnakeView.READY);
 58 
 59  display.setCurrent(mSnakeView);
 60 
 61  }
 62 
 63  protected   void  destroyApp( boolean  arg0)  throws  MIDletStateChangeException {
 64 
 65  mSnakeView.saveState();
 66 
 67  }
 68 
 69  protected   void  pauseApp() {
 70 
 71  mSnakeView.setMode(SnakeView.PAUSE);
 72 
 73  }
 74 
 75  protected   void  startApp()  throws  MIDletStateChangeException {
 76 
 77  //  检查存贮状态以确定是重新开始还是恢复状态
 78 
 79  Log.debug( " startApp(), BaseRMS.FIRST= " + BaseRMS.FIRST);
 80 
 81  if  (BaseRMS.FIRST) {
 82 
 83  //  存储状态为空,说明刚启动可以切换到准备状态
 84 
 85  mSnakeView.setMode(SnakeView.READY);
 86 
 87  else  {
 88 
 89  //  已经保存过,那么就去恢复原有状态
 90 
 91  //  恢复状态
 92 
 93  if  ( ! mSnakeView.restoreState()) {
 94 
 95  //  恢复状态不成功,设置状态为暂停
 96 
 97  mSnakeView.setMode(SnakeView.PAUSE);
 98 
 99  }
100 
101  }
102 
103  }
104 
105  }

 

 

本次就大概介绍这么多,源代码将在下次放出。下次主要讲解源代码的存储和维护,敬请期待。

你可能感兴趣的:(android)