zoukankan      html  css  js  c++  java
  • 从android游戏框架看其生命周期

    同类型游戏 生命周期 讲解的博客还有 :  从零开始Android游戏编程(第二版) 第九章 游戏程序的生命周期

    书本上, 网络上android游戏框架比比皆是, 但是都未深入其生命周期, 下面只适用于 单机版,网络版好像不适用       

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

    Activity 

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

    surfaceView 

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

    游戏控制线程 

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

    布局文件 

    main.xml
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <FrameLayout
     3     xmlns:android="http://schemas.android.com/apk/res/android"
     4     android:orientation="vertical"
     5     android:layout_width="fill_parent"
     6     android:layout_height="fill_parent">
     7     <air.frame.GameSurfaceView
     8         android:id="@+id/gameview"
     9         android:layout_width="fill_parent"
    10         android:layout_height="fill_parent"/>
    11     <RelativeLayout
    12         android:layout_width="fill_parent"
    13         android:layout_height="fill_parent">
    14         <TextView
    15             android:id="@+id/textview"
    16             android:layout_width="wrap_content"
    17             android:layout_height="wrap_content"
    18             android:layout_centerInParent="true"
    19             android:gravity="center_horizontal"
    20             android:textColor="#88ffffff"
    21             android:textSize="24sp"/>
    22     </RelativeLayout>
    23 </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)。

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 二元函数
    Java实现 蓝桥杯VIP 算法训练 二元函数
    Java实现 蓝桥杯VIP 算法训练 二元函数
    Java实现 蓝桥杯VIP 算法训练 二元函数
    Java实现 蓝桥杯VIP 算法训练 二元函数
    创建虚拟桌面的代码(重启桌面进程)(使用GetThreadDesktop,CreateDesktop,SetThreadDesktop等函数)
    SEH and C++ Exceptions,自定义CSeException
    VC自动与Internet时间服务器同步更新
    VS2005 检测内存泄漏的方法(转载)
    VC判断当前用户有无Administrator的权限(用EqualSid API函数判断与Admin是否在一个组的Sid)
  • 原文地址:https://www.cnblogs.com/firecode/p/2620348.html
Copyright © 2011-2022 走看看