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

来源:互联网 发布:播音员声音软件 编辑:程序博客网 时间:2024/04/29 03:11

书本上, 网路上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 GameActivityextends 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

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 GameSurfaceViewextends 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             @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 }

 

游戏控制线程

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     // 游戏状态值: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>

 

生命周期初步信息

如上所示: 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

原创粉丝点击