书本上, 网路上android游戏框架比比皆是, 但是都未深入其生命周期,

以下是我选取的基于servaceView的android游戏框架,

Activity

GameActivity.java
  1 package air.frame;
2
3 import android.app.Activity;
4 import android.os.Bundle;
5 import android.util.Log;
6 import android.view.Menu;
7 import android.view.MenuItem;
8 import android.widget.TextView;
9
10 publicclass GameActivity extends Activity {
11 private GameSurfaceView gameSurfaceView;
12 private GameThread gameThread;
13 publicstaticfinal String TAG ="GameFrame";
14
15 @Override
16 publicvoid onCreate(Bundle savedInstanceState) {
17 super.onCreate(savedInstanceState);
18 setContentView(R.layout.main);
19 gameSurfaceView = (GameSurfaceView) this.findViewById(R.id.gameview);
20 gameThread = gameSurfaceView.getThread();
21 gameSurfaceView.setTextView((TextView) findViewById(R.id.textview));
22
23 Log.d(TAG, "onCreate");
24
25 if (savedInstanceState ==null) {
26 // 游戏第一次启动时,初始化游戏状态
27 gameThread.doStart();
28 Log.d(TAG, "SIS is null");
29 } else {
30 // 从其他应用界面切回游戏时,如果Activity重新创建,则恢复上次切出游戏时的各项数据
31 gameThread.restoreState(savedInstanceState);
32 Log.d(TAG, "SIS is not null");
33 }
34 }
35
36 /**
37 * 当Activity被切换到后台时调用,存储Activity重新创建时需要恢复的游戏数据
38 */
39 @Override
40 protectedvoid onSaveInstanceState(Bundle outState) {
41 super.onSaveInstanceState(outState);
42 gameThread.saveState(outState);
43 Log.d(TAG, "SIS called");
44 }
45
46 /**
47 * 当Activity被切换到后台时调用,在这里对游戏做"暂停"的处理
48 */
49 @Override
50 protectedvoid onPause() {
51 super.onPause();
52 // 暂停游戏
53 Log.d(TAG, "onPause");
54 gameSurfaceView.getThread().pause();
55 }
56
57 /**
58 * 当Activity切换到前台时调用
59 */
60 @Override
61 protectedvoid onResume() {
62 super.onResume();
63 // 游戏结束暂停状态,游戏正常进行
64 Log.d(TAG, "onResume");
65 gameSurfaceView.getThread().unpause();
66 }
67
68 /**
69 * 创建游戏菜单
70 */
71 @Override
72 publicboolean onCreateOptionsMenu(Menu menu) {
73 // TODO Auto-generated method stub
74 Log.d(TAG, "onCreateOptionsMenu");
75 returnsuper.onCreateOptionsMenu(menu);
76 }
77
78 /**
79 * 定义游戏菜单的点击事件处理
80 */
81 @Override
82 publicboolean onOptionsItemSelected(MenuItem item) {
83 // TODO Auto-generated method stub
84 Log.d(TAG, "onOptionsItemSelected");
85 returnsuper.onOptionsItemSelected(item);
86 }
87
88 @Override
89 protectedvoid onRestart() {
90 Log.d(TAG, "onRestart");
91 super.onRestart();
92 }
93
94 @Override
95 protectedvoid onRestoreInstanceState(Bundle savedInstanceState) {
96 Log.d(TAG, "onRestoreInstanceState");
97 super.onRestoreInstanceState(savedInstanceState);
98 }
99
100 @Override
101 protectedvoid onStart() {
102 Log.d(TAG, "onStart");
103 super.onStart();
104 }
105
106 @Override
107 protectedvoid onStop() {
108 Log.d(TAG, "onStop");
109 super.onStop();
110 }
111
112 @Override
113 protectedvoid onDestroy() {
114 super.onDestroy();
115 Log.d(TAG, "onDestroy");
116
117 // 停止游戏
118 gameThread.setRunning(false);
119 boolean retry =true;
120 while (retry) {
121 try {
122 // 阻塞Activity的主线程直到游戏线程执行完
123 gameThread.join();
124 retry =false;
125 } catch (InterruptedException e) {
126 }
127 }
128 }
129 }

surfaceView

GameSurfaceView.java
 1 package air.frame;
2
3 import android.content.Context;
4 import android.os.Handler;
5 import android.os.Message;
6 import android.util.AttributeSet;
7 import android.util.Log;
8 import android.view.KeyEvent;
9 import android.view.SurfaceHolder;
10 import android.view.SurfaceView;
11 import android.view.SurfaceHolder.Callback;
12 import android.widget.TextView;
13
14 publicclass GameSurfaceView extends SurfaceView implements Callback {
15 private GameThread gameThread;
16 private TextView textview;
17
18 final String TAG = GameActivity.TAG;
19
20 public GameSurfaceView(Context context, AttributeSet attrs) {
21 super(context, attrs);
22 SurfaceHolder holder = getHolder();
23 holder.addCallback(this);
24 gameThread =new GameThread(holder, context, new Handler() {
25 @Override
26 publicvoid handleMessage(Message m) {
27 textview.setText(m.getData().getString("text"));
28 }
29 });
30 // 设置可获得焦点,确保能捕获到KeyEvent
31 setFocusable(true);
32 }
33
34 /**
35 * 获取一个Activity传来的View协助SurfaceView显示游戏视图,View的具体类型可以根据游戏需要来定
36 */
37 publicvoid setTextView(TextView view) {
38 this.textview = view;
39 }
40
41 public GameThread getThread() {
42 return gameThread;
43 }
44
45 @Override
46 publicboolean onKeyDown(int keyCode, KeyEvent event) {
47 return gameThread.doKeyDown(keyCode, event);
48 }
49
50 @Override
51 publicboolean onKeyUp(int keyCode, KeyEvent event) {
52 return gameThread.doKeyUp(keyCode, event);
53 }
54
55 /**
56 * 当SurfaceView得到或失去焦点时调用,使游戏暂停/恢复运行,
57 */
58 @Override
59 publicvoid onWindowFocusChanged(boolean hasWindowFocus) {
60 if (!hasWindowFocus) {
61 gameThread.pause();
62 } else {
63 gameThread.unpause();
64 }
65 }
66
67 @Override
68 publicvoid surfaceChanged(SurfaceHolder holder, int format, int width,
69 int height) {
70 Log.d(TAG, "surfaceChanged()");
71 gameThread.setSurfaceSize(width, height);
72 gameThread.setRunning(true);
73 if (gameThread.isAlive()) {
74 Log.v(this.getClass().getName(), "unpause gameThread");
75 gameThread.unpause();
76 } else {
77 Log.v(this.getClass().getName(), "start gameThread");
78 gameThread.start();
79 }
80 }
81
82 @Override
83 publicvoid surfaceCreated(SurfaceHolder holder) {
84 Log.d(TAG, "surfaceCreated()");
85 }
86
87 /**
88 * 为防止surface还会被创建(比如来电)导致gameThread再次启动出现错误,且Activity的onPause方法中已做暂停处理,
89 * 这边不对gameThread做处理
90 *
91 * @param holder
92 */
93 @Override
94 publicvoid surfaceDestroyed(SurfaceHolder holder) {
95 Log.d(TAG, "surfaceDestroyed");
96 }
97 }

游戏控制线程

GameThread.java
  1 package air.frame;
2
3 import android.content.Context;
4 import android.graphics.Canvas;
5 import android.os.Bundle;
6 import android.os.Handler;
7 import android.util.Log;
8 import android.view.KeyEvent;
9 import android.view.SurfaceHolder;
10
11 publicclass GameThread extends Thread {
12 final String TAG = GameActivity.TAG;
13
14 // 游戏状态值:ready
15 publicfinalstaticint GS_READY =0;
16 // 游戏线程每执行一次需要睡眠的时间
17 privatefinalstaticint DELAY_TIME =100;
18 // 上下文,方便获取到应用的各项资源,如图片、音乐、字符串等
19 private Context context;
20 // 与Activity其他View交互用的handler
21 private Handler handler;
22 // 由SurfaceView提供的SurfaceHolder
23 private SurfaceHolder surfaceHolder;
24 // 游戏线程运行开关
25 privateboolean running =false;
26 // 游戏状态
27 privateint gameState;
28 // 当前surface/canvas的高度,在surfaceChanged方法中被设置
29 privateint mCanvasHeight =1;
30 // 当前surface/canvas的宽度,在surfaceChanged方法中被设置
31 privateint mCanvasWidth =1;
32
33 /**
34 * 游戏是否暂停
35 */
36 privateboolean isPaused =false;
37
38 public GameThread(SurfaceHolder holder, Context context, Handler handler) {
39 this.surfaceHolder = holder;
40 this.context = context;
41 this.handler = handler;
42 }
43
44 /**
45 * 设置游戏状态
46 *
47 * @param mode 游戏状态
48 */
49 publicvoid setState(int mode) {
50 synchronized (surfaceHolder) {
51 setState(mode, null);
52 }
53 }
54
55 /**
56 * 设置游戏状态
57 *
58 * @param mode 游戏状态
59 * @param message 设置游戏状态时的附加文字信息
60 */
61 publicvoid setState(int mode, CharSequence message) {
62 synchronized (surfaceHolder) {
63 // TODO
64 }
65 }
66
67 /**
68 * 暂停游戏
69 */
70 publicvoid pause() {
71 synchronized (surfaceHolder) {
72 isPaused =true;
73 }
74 }
75
76 /**
77 * 恢复运行游戏
78 */
79 publicvoid unpause() {
80 // 如果游戏中有时间,别忘记应将其在这里调整到正常
81 synchronized (surfaceHolder) {
82 isPaused =false;
83 }
84 }
85
86 /**
87 * 当Activity因销毁而被重新创建时,在这里恢复游戏上次运行的数据
88 *
89 * @param saveState Activity传来的保存游戏数据的容器
90 */
91 publicvoid restoreState(Bundle saveState) {
92 // TODO
93 }
94
95 /**
96 * 在Activity切到后台时保存游戏的数据
97 *
98 * @param outState 保存游戏数据的容器
99 */
100 publicvoid saveState(Bundle outState) {
101 // TODO
102 }
103
104 /**
105 * 设置游戏线程运行开关
106 *
107 * @param b 开/关
108 */
109 publicvoid setRunning(boolean b) {
110 running = b;
111 }
112
113 /**
114 * 处理按下按键的事件
115 *
116 * @param keyCode 按键事件动作值
117 * @param msg 按键事件对象
118 * @return 是否处理完
119 */
120 publicboolean doKeyDown(int keyCode, KeyEvent msg) {
121 synchronized (surfaceHolder) {
122 // TODO
123 returnfalse;
124 }
125 }
126
127 /**
128 * 处理弹起按键的事件
129 *
130 * @param keyCode 按键事件动作值
131 * @param msg 按键事件对象
132 * @return 是否处理完
133 */
134 publicboolean doKeyUp(int keyCode, KeyEvent msg) {
135 synchronized (surfaceHolder) {
136 // TODO
137 }
138 returnfalse;
139 }
140
141 /**
142 * 设置surface/canvas的宽度和高度
143 *
144 * @param width 由SurfaceHolder传来的宽度
145 * @param height 由SurfaceHolder传来的高度
146 */
147 publicvoid setSurfaceSize(int width, int height) {
148 // synchronized to make sure these all change atomically
149 synchronized (surfaceHolder) {
150 mCanvasWidth = width;
151 mCanvasHeight = height;
152 // 不要忘记每次画布的宽度和高度改变时, 在这里对图片等资源做缩放等相关适配屏幕的处理
153 // TODO
154 }
155 }
156
157 publicvoid run() {
158 while (running) {
159 if (!isPaused) {
160 Canvas c =null;
161 try {
162 c = surfaceHolder.lockCanvas(null);
163 synchronized (surfaceHolder) {
164 doDraw(c);
165 }
166 logic();
167 } finally {
168 if (c !=null) {
169 surfaceHolder.unlockCanvasAndPost(c);
170 }
171 }
172 try {
173 Thread.sleep(DELAY_TIME);
174 } catch (InterruptedException e) {
175 e.printStackTrace();
176 }
177 }
178 }
179 }
180
181 /**
182 * 游戏逻辑处理
183 */
184 publicvoid logic() {
185 Log.v(this.getClass().getName(), "logic");
186 // TODO
187 }
188
189 /**
190 * 游戏绘画
191 */
192 privatevoid doDraw(Canvas canvas) {
193 Log.v(this.getClass().getName(), "doDraw");
194 // TODO
195 }
196
197
198 /**
199 * 初始化游戏开始时的参数
200 */
201 publicvoid doStart() {
202 // TODO
203 }
204 }

布局文件

main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation
="vertical"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent">
<air.frame.GameSurfaceView
android:id="@+id/gameview"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent"/>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height
="fill_parent">
<TextView
android:id="@+id/textview"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_centerInParent
="true"
android:gravity
="center_horizontal"
android:textColor
="#88ffffff"
android:textSize
="24sp"/>
</RelativeLayout>
</FrameLayout>

生命周期初步信息

从android游戏框架看其生命周期!_第1张图片

如上所示:surfaceView的生命周期寄托在activity的生命周期之上

附:

activity现场保护:(可以用于实现游戏暂停, 也可以持久化存储现场, 在surfaceCreate里面判断恢复)

http://www.cnblogs.com/wumao/archive/2011/04/25/2026483.html

以下链接是恢复现场的几种方法!

http://www.cnblogs.com/xirihanlin/archive/2009/08/05/1539420.html

除了官方的生命周期图之外, 如下链接对生命周期的见解, 我觉得不错!

http://www.cnblogs.com/kofi1122/archive/2011/04/10/2011772.html

另外, 两个不常用的状态:

onSaveInstanceState: Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key) /当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按返回键的时候。

onSaveInstanceState触发的时机

1、当用户按下HOME键时。

这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则


2、长按HOME键,选择运行其他的程序时。


3、按下电源按键(关闭屏幕显示)时。


4、从activity A中启动一个新的activity时。


5、屏幕方向切换时,例如从竖屏切换到横屏时。

在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行

总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。

onRestoreInstanceState:需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执


另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原(如例子所示Line25~Line33)。

更多相关文章

  1. [Android引擎]Android游戏框架AndE…
  2. Android游戏引擎-Rokon
  3. android 8.1 修改禁止状态栏下拉
  4. Android中一个Activity多个intent-filter的调用方法

随机推荐

  1. Android(安卓)+ Eclipse + NDK + cygwin
  2. Android(安卓)Studio打不开的问题
  3. 在 android 上运行 python 的方法
  4. Android(安卓)设置DrawableRight和Drawab
  5. android:padding和android:margin的用法
  6. Android(安卓)TableLayout 实现边框
  7. Android的多媒体框架OpenCore介绍
  8. Android横竖屏切换实例总结
  9. Android中Activity四种启动模式详解
  10. android各个版本特性和市场占有率(2012年5