书本上, 网路上android游戏框架比比皆是, 但是都未深入其生命周期,
以下是我选取的基于servaceView的android游戏框架,
Activity
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 publicstatic final String TAG= "GameFrame";14 15 @Override16 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 @Override40 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 @Override50 protectedvoid onPause() {51 super.onPause();52 // 暂停游戏53 Log.d(TAG,"onPause");54 gameSurfaceView.getThread().pause();55 }56 57 /**58 * 当Activity切换到前台时调用59 */60 @Override61 protectedvoid onResume() {62 super.onResume();63 // 游戏结束暂停状态,游戏正常进行64 Log.d(TAG,"onResume");65 gameSurfaceView.getThread().unpause();66 }67 68 /**69 * 创建游戏菜单70 */71 @Override72 publicboolean onCreateOptionsMenu(Menu menu) {73 // TODO Auto-generated method stub74 Log.d(TAG,"onCreateOptionsMenu");75 returnsuper.onCreateOptionsMenu(menu);76 }77 78 /**79 * 定义游戏菜单的点击事件处理80 */81 @Override82 publicboolean onOptionsItemSelected(MenuItem item) {83 // TODO Auto-generated method stub84 Log.d(TAG,"onOptionsItemSelected");85 returnsuper.onOptionsItemSelected(item);86 }87 88 @Override89 protectedvoid onRestart() {90 Log.d(TAG, "onRestart");91 super.onRestart();92 }93 94 @Override95 protectedvoid onRestoreInstanceState(Bundle savedInstanceState) {96 Log.d(TAG, "onRestoreInstanceState");97 super.onRestoreInstanceState(savedInstanceState);98 }99 100 @Override101 protectedvoid onStart() {102 Log.d(TAG, "onStart");103 super.onStart();104 }105 106 @Override107 protectedvoid onStop() {108 Log.d(TAG, "onStop");109 super.onStop();110 }111 112 @Override113 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
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 SurfaceViewimplements 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 @Override26 publicvoid handleMessage(Message m) {27 textview.setText(m.getData().getString("text"));28 }29 });30 // 设置可获得焦点,确保能捕获到KeyEvent31 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 @Override46 publicboolean onKeyDown(int keyCode, KeyEvent event) {47 return gameThread.doKeyDown(keyCode, event);48 }49 50 @Override51 publicboolean onKeyUp(int keyCode, KeyEvent event) {52 return gameThread.doKeyUp(keyCode, event);53 }54 55 /**56 * 当SurfaceView得到或失去焦点时调用,使游戏暂停/恢复运行,57 */58 @Override59 publicvoid onWindowFocusChanged(boolean hasWindowFocus) {60 if (!hasWindowFocus) {61 gameThread.pause();62 } else {63 gameThread.unpause();64 }65 }66 67 @Override68 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 @Override83 publicvoid surfaceCreated(SurfaceHolder holder) {84 Log.d(TAG, "surfaceCreated()");85 }86 87 /**88 * 为防止surface还会被创建(比如来电)导致gameThread再次启动出现错误,且Activity的onPause方法中已做暂停处理,89 * 这边不对gameThread做处理90 * 91 * @param holder92 */93 @Override94 publicvoid surfaceDestroyed(SurfaceHolder holder) {95 Log.d(TAG, "surfaceDestroyed");96 }97 }
游戏控制线程
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 GameThreadextends Thread {12 final String TAG= GameActivity.TAG;13 14 // 游戏状态值:ready15 publicfinal staticint GS_READY= 0;16 // 游戏线程每执行一次需要睡眠的时间17 privatefinal staticint DELAY_TIME=100;18 // 上下文,方便获取到应用的各项资源,如图片、音乐、字符串等19 private Context context;20 // 与Activity其他View交互用的handler21 private Handler handler;22 // 由SurfaceView提供的SurfaceHolder23 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 // TODO64 }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 // TODO93 }94 95 /**96 * 在Activity切到后台时保存游戏的数据97 * 98 * @param outState 保存游戏数据的容器99 */100 publicvoid saveState(Bundle outState) {101 // TODO102 }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 // TODO123 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 // TODO137 }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 atomically149 synchronized (surfaceHolder) {150 mCanvasWidth= width;151 mCanvasHeight= height;152 // 不要忘记每次画布的宽度和高度改变时, 在这里对图片等资源做缩放等相关适配屏幕的处理153 // TODO154 }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 // TODO187 }188 189 /**190 * 游戏绘画191 */192 privatevoid doDraw(Canvas canvas) {193 Log.v(this.getClass().getName(),"doDraw");194 // TODO195 }196 197 198 /**199 * 初始化游戏开始时的参数200 */201 publicvoid doStart() {202 // TODO203 }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>
生命周期初步信息
如上所示: 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)。
转自:
http://www.cnblogs.com/HelloHolyWorld/archive/2011/09/19/2181890.html
转载于:https://www.cnblogs.com/ileimingGG/archive/2012/06/15/7435810.html
相关资源:Android游戏框架(基础版)