从android游戏框架看其生命周期!

mac2022-06-30  79

书本上, 网路上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游戏框架(基础版)
最新回复(0)