Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> 【貪吃蛇—Java程序員寫Android游戲】系列 3. 用J2ME實現Android的Snake Sample詳解

【貪吃蛇—Java程序員寫Android游戲】系列 3. 用J2ME實現Android的Snake Sample詳解

編輯:Android開發實例

本次會詳細講解將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 }

 

 

本次就大概介紹這麼多,源代碼將在下次放出。下次主要講解源代碼的存儲和維護,敬請期待。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved