Android2D游戏开发十九 (必看篇)剖析Back与Home键及异常处理 2ne1 come back home

在这里先向各位童鞋道个歉!我解释下:当我在给大家讲解的时候会附带上源码,可是这个源码是演示代码,为了让大家看的清楚,所以我会尽可能把一些与其无关的删掉,但是发现演示代码还是被一些童鞋们效仿,导致不少童鞋问我为什么程序执行后切入后台重新进入会报异常的问题!(这里我就全面讲解下运行机制,希望以后大家有类似问题自己就能解决了哈~)

切入后台操作比如点击HOME按键,点击返回按键...

那么重新进入程序报异常主要Surfaceiew 有两点会报异常:

第一:提交画布异常!如下图(模拟器错误提示,以及Logcat Detail)



解决代码:

view sourceprint?01 public void draw() {

02 try {

03 canvas = sfh.lockCanvas();

04 if (canvas != null) {

05 canvas.drawColor(Color.WHITE);

06 canvas.drawBitmap(bmp, bmp_x, bmp_y, paint);

07 }

08 } catch (Exception e) {

09 Log.v("Himi", "draw is Error!");

10 } finally {//备注1

11 if (canvas != null)//备注2

12 sfh.unlockCanvasAndPost(canvas);

13 }

14 }

先看备注1这里,之前的文章中我给大家解释过为什么要把 sfh.unlockCanvasAndPost(canvas); 写在finally中,主要是为了保证能正常的提交画

布.今天主要说说备注2,这里一定要判定下canvas是否为空,因为当程序切入后台的时候,canvas是获取不到的!那么canvas一旦为空,提交画

布这里就会出现参数异常的错误!

下面来说另外一种情况:线程启动异常!如下图(模拟器错误提示,以及Logcat Detail)

  

这种异常只是在当你程序运行期间点击Home按钮后再次进入程序的时候报的异常,异常说咱们的线程已经启动!为什么返回按钮就没事?

OK,下面我们就要来先详细讲解一下Android中Back和Home按键的机制!然后分析问题,并且解决问题!

先看下面MySurfaceViewAnimation.Java的类中的代码:view sourceprint?01 package com.himi;

02 import java.util.Vector;

03 import android.content.Context;

04 import android.graphics.Bitmap;

05 import android.graphics.BitmapFactory;

06 import android.graphics.Canvas;

07 import android.graphics.Color;

08 import android.graphics.Paint;

09 import android.util.Log;

10 import android.view.GestureDetector;

11 import android.view.MotionEvent;

12 import android.view.SurfaceHolder;

13 import android.view.SurfaceView;

14 import android.view.View;

15 import android.view.GestureDetector.OnGestureListener;

16 import android.view.SurfaceHolder.Callback;

17 import android.view.View.OnTouchListener;

18 /**

19 *@author Himi

20 *@SurfaceView 运行机制详解

21 */

22 public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable {

23 private Thread th;

24 private SurfaceHolder sfh;

25 private Canvas canvas;

26 private Paint paint;

27 private Bitmap bmp;

28 private int bmp_x, bmp_y;

29 public MySurfaceViewAnimation(Context context) {

30 super(context);

31 this.setKeepScreenOn(true);

32 bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream);

33 sfh = this.getHolder();

34 sfh.addCallback(this);

35 paint = new Paint();

36 paint.setAntiAlias(true);

37 this.setLongClickable(true);

38 th = new Thread(this, "himi_Thread_one");

39 Log.e("Himi", "surfaceChanged");

40 }

41 public void surfaceCreated(SurfaceHolder holder) {

42 th.start();

43 Log.e("Himi", "surfaceCreated");

44 }

45 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

46 Log.e("Himi", "surfaceChanged");

47 }

48 public void surfaceDestroyed(SurfaceHolder holder) {

49 Log.e("Himi", "surfaceDestroyed");

50 }

51 public void draw() {

52 try {

53 canvas = sfh.lockCanvas();

54 if (canvas != null) {

55 canvas.drawColor(Color.WHITE);

56 canvas.drawBitmap(bmp, bmp_x, bmp_y, paint);

57 }

58 } catch (Exception e) {

59 Log.v("Himi", "draw is Error!");

60 } finally {//备注1

61 if (canvas != null)//备注2

62 sfh.unlockCanvasAndPost(canvas);

63 }

64 }

65 public void run() {

66 while (true) {

67 draw();

68 try {

69 Thread.sleep(100);

70 } catch (Exception ex) {

71 }

72 }

73 }

74 }

 

以上是我们常用的自定义SurfaceView,并且使用Runnable接口老框架了不多说了,其中我在本类的构造、创建、状态改变、消亡函数都加上打印!

OK,下面看第一张图:(刚运行程序)



上图的左边部分是Dubug!这里显示我们有一条线程在运行,名字叫"himi_Thread_one";

上图的左边部分是LogCat日志!大家很清晰的看到,当第一次进入程序的时候,会先进入view构造函数、然后是创建view、然后是view状态改变、OK,这个大家都知道!

下面我来点击Home(手机上的小房子)按键!这时程序处于后台!然后重新进入程序的过程!



上图可以看出我们的线程还是一条、这里主要观察从点击home到再次进入程序的过程:(过程如下):

点击home 调用了view销毁、然后进入程序会先进入view创建,最后是view状态改变!

上面的过程很容易理解,重要的角色上场了~Back 按钮!点我点击Back按钮看看发生了什么!



 

先看左边的Debug一栏,多了一条线程! 看LogCat发现比点击Home按键多调用了一次构造函数!

好了,从我们测试的程序来看,无疑,点击Home 和 点击 Back按钮再次进入程序的时候,步骤是不一样的,线程数量也变了!

那么这里就能解释为什么我们点击Back按钮不异常、点击Home会异常了!

原因:因为点击Back按钮再次进入程序的时候先进入的是view构造函数里,那么就是说这里又new了一个线程出来,并启动!那么而我们点击Home却不一样了,因为点击home之后再次进入程序不会进入构造函数,而是直接进入了view创建这个函数,而在view创建这个函数中我们有个启动线程的操作,其实第一次启动程序的线程还在运行,so~这里就一定异常了,说线程已经启动!

有些童鞋会问,我们为何不把th = new Thread(this, "himi_Thread_one");放在view创建函数中不就好了??!!

没错,可以!但是当你反复几次之后你发现你的程序中会多出很多条进程!(如下图)



 

虽然可以避免出现线程已经启动的异常,很明显这不是我们想要的结果!

那么下面给大家介绍最合适的解决方案:

修改MySurfaceViewAnimation.java

view sourceprint?01 package com.himi;

02 import android.content.Context;

03 import android.graphics.Bitmap;

04 import android.graphics.BitmapFactory;

05 import android.graphics.Canvas;

06 import android.graphics.Color;

【Android2D游戏开发十九】(必看篇)剖析Back与Home键及异常处理 2ne1 come back home
07 import android.graphics.Paint;

08 import android.util.Log;

09 import android.view.SurfaceHolder;

10 import android.view.SurfaceView;

11 import android.view.SurfaceHolder.Callback;

12 /**

13 *@author Himi

14 *@SurfaceView 运行机制详解(修改后的最佳方式)

15 */

16 public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable {

17 private Thread th;

18 private SurfaceHolder sfh;

19 private Canvas canvas;

20 private Paint paint;

21 private Bitmap bmp;

22 private int bmp_x, bmp_y;

23 private boolean himi; //备注1

24 public MySurfaceViewAnimation(Context context) {

25 super(context);

26 this.setKeepScreenOn(true);

27 bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream);

28 sfh = this.getHolder();

29 sfh.addCallback(this);

30 paint = new Paint();

31 paint.setAntiAlias(true);

32 this.setLongClickable(true);

33 Log.e("Himi", "surfaceChanged");

34 }

35 public void surfaceCreated(SurfaceHolder holder) {

36 himi = true;

37 th = new Thread(this, "himi_Thread_one");//备注2

38 th.start();

39 Log.e("Himi", "surfaceCreated");

40 }

41 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

42 Log.e("Himi", "surfaceChanged");

43 }

44 public void surfaceDestroyed(SurfaceHolder holder) {

45 himi = false;//备注3

46 Log.e("Himi", "surfaceDestroyed");

47 }

48 public void draw() {

49 try {

50 canvas = sfh.lockCanvas();

51 if (canvas != null) {

52 canvas.drawColor(Color.WHITE);

53 canvas.drawBitmap(bmp, bmp_x, bmp_y, paint);

54 }

55 } catch (Exception e) {

56 Log.v("Himi", "draw is Error!");

57 } finally {

58 if (canvas != null)

59 sfh.unlockCanvasAndPost(canvas);

60 }

61 }

62 public void run() {

63 while (himi) {//备注4

64 draw();

65 try {

66 Thread.sleep(100);

67 } catch (Exception ex) {

68 }

69 }

70 }

71 }

这里修改的地方有以下几点:

1. 我们都知道一个线程启动后,只要run方法执行结束,线程就销毁了,所以我增加了一个布尔值的成员变量 himi(备注1),这里可以控制我们的线程消亡的一个开关!(备注4)

2.在启动线程之前,设置这个布尔值为ture,让线程一直运行.

3.在view销毁时,设置这个布尔值为false,销毁当前线程!(备注3)

4.把我们创建线程实例也放在view创建中!(备注2),为什么要放这里,因为不管点击Back还是Home都会执行view创建函数的!如果你写在构造里,那么点击home的时候就又空指针啦!

OK,这里图和解释够详细了,希望大家以后真正开发一款游戏的时候,一定要严谨代码,不要留有后患哈~

 

  

爱华网本文地址 » http://www.aihuau.com/a/25101012/116734.html

更多阅读

最完美的爱情 十部必看经典小说言情

最完美的爱情——简介最完美的爱情不是在一起疯天疯地,在一起吃喝玩乐!而是一种心与心的交流,情与情的交融,当然这其中离不开心里,生理上的欢愉!怎样才能达到完美的爱情呢?那必须是你中有我,我中有你!一种默契,对彼此的真诚与了解!最完美

何以笙夏默 十部必看经典小说言情

——只要不去想,肤浅的快乐其实很容易。——你也知道痛吗,痛是午夜梦回后抓不住她轻颦浅笑的巨大空洞。——赵默笙,我是疯了才会让你这样践踏。——给我一个理由,告诉我,你爱我。——从现在开始,就算我们一辈

看电影学英语必看的高效方法 十大必看狙击手电影

学了几十年的 英语却不会说,说出来也是别人听不懂的句子,究其原因,还是因为自己把语言当成知识来学了。看电影可以激起人们的兴趣,电影可以营造出一种逼真的语言环境,电影是沟通文化的桥梁,电影有助于提高听力和口语能力,培养较强的语感、

我在回忆里等你 十部必看经典小说言情

你相信时光能够倒流吗,假如可以回到过去,你会做什么?她说:“我要去找当年的司徒玦,对她说:一定一定不要爱上姚起云。如果还有人遇到当年的姚起云,请你带我告诉他:2001年7月5日,直到那一天的最后一秒,我都还在这里等着他。”所以,绝望也不过如

声明:《Android2D游戏开发十九 (必看篇)剖析Back与Home键及异常处理 2ne1 come back home》为网友鹿畔阳光分享!如侵犯到您的合法权益请联系我们删除