【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理!...

Himi 原创, 欢迎转载,转载请在明显处注明! 谢谢。

原文地址:http://blog.youkuaiyun.com/xiaominghimi/archive/2011/01/18/6149816.aspx

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

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

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

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

解决代码:

public void draw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); canvas.drawBitmap(bmp, bmp_x, bmp_y, paint); } } catch (Exception e) { Log.v("Himi", "draw is Error!"); } finally {//备注1 if (canvas != null)//备注2 sfh.unlockCanvasAndPost(canvas); } }

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

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

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

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

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

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

先看下面MySurfaceViewAnimation.java的类中的代码:

package com.himi; import java.util.Vector; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.view.GestureDetector.OnGestureListener; import android.view.SurfaceHolder.Callback; import android.view.View.OnTouchListener; /** *@author Himi *@SurfaceView 运行机制详解 */ public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable { private Thread th; private SurfaceHolder sfh; private Canvas canvas; private Paint paint; private Bitmap bmp; private int bmp_x, bmp_y; public MySurfaceViewAnimation(Context context) { super(context); this.setKeepScreenOn(true); bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setAntiAlias(true); this.setLongClickable(true); th = new Thread(this, "himi_Thread_one"); Log.e("Himi", "surfaceChanged"); } public void surfaceCreated(SurfaceHolder holder) { th.start(); Log.e("Himi", "surfaceCreated"); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.e("Himi", "surfaceChanged"); } public void surfaceDestroyed(SurfaceHolder holder) { Log.e("Himi", "surfaceDestroyed"); } public void draw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); canvas.drawBitmap(bmp, bmp_x, bmp_y, paint); } } catch (Exception e) { Log.v("Himi", "draw is Error!"); } finally {//备注1 if (canvas != null)//备注2 sfh.unlockCanvasAndPost(canvas); } } public void run() { while (true) { draw(); try { Thread.sleep(100); } catch (Exception ex) { } } } }

以上是我们常用的自定义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

package com.himi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.SurfaceHolder.Callback; /** *@author Himi *@SurfaceView 运行机制详解(修改后的最佳方式) */ public class MySurfaceViewAnimation extends SurfaceView implements Callback, Runnable { private Thread th; private SurfaceHolder sfh; private Canvas canvas; private Paint paint; private Bitmap bmp; private int bmp_x, bmp_y; private boolean himi; //备注1 public MySurfaceViewAnimation(Context context) { super(context); this.setKeepScreenOn(true); bmp = BitmapFactory.decodeResource(getResources(), R.drawable.himi_dream); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setAntiAlias(true); this.setLongClickable(true); Log.e("Himi", "surfaceChanged"); } public void surfaceCreated(SurfaceHolder holder) { himi = true; th = new Thread(this, "himi_Thread_one");//备注2 th.start(); Log.e("Himi", "surfaceCreated"); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { Log.e("Himi", "surfaceChanged"); } public void surfaceDestroyed(SurfaceHolder holder) { himi = false;//备注3 Log.e("Himi", "surfaceDestroyed"); } public void draw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { canvas.drawColor(Color.WHITE); canvas.drawBitmap(bmp, bmp_x, bmp_y, paint); } } catch (Exception e) { Log.v("Himi", "draw is Error!"); } finally { if (canvas != null) sfh.unlockCanvasAndPost(canvas); } } public void run() { while (himi) {//备注4 draw(); try { Thread.sleep(100); } catch (Exception ex) { } } } }

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

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

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

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

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

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

鱼鹰优化算法(OOA)详解:从猛禽捕食智能到优化算法实现 鱼鹰优化算法(Osprey Optimization Algorithm, OOA)是2023年提出的一种新型元启发式优化算法,灵感来源于鱼鹰(一种中型猛禽)高效的捕食策略。算法模拟了鱼鹰从空中识别水下鱼类位置并俯冲捕食,然后将捕获的鱼带至安全位置享用的全过程,以此抽象出全局探索和局部开发两个核心阶段。OOA算法具有参数少、结构简单、收敛速度快、全局寻优能力强等特点。自提出以来,已在函数优化、机器学习参数调优(如CatBoost模型)、路径规划等多个领域展现出良好性能,为解决复杂优化问题提供了新的有效工具。 阅读详情

相关推荐

Xilinx Blockset Counter计数器模块使用及参数配置

本文详细介绍了Simulink中Xilinx Blockset库Counter模块的使用以及参数说明。

白码王子小张的博客 1096

有关安卓的Activity前后台切换

本文仅是AI问答记录备忘。

x5237732的博客 2786

海思方案定制hi3531dv200/SS528 DVR方案解析:从硬件选型到编解码实战应用

海思方案,Hi3518EV100,Hi3518CV100,Hi3515CV100,Hi3516CV100,Hi3516ECV100,Hi3516D,Hi3516A,Hi3519,Hi3520D,Hi3521A,Hi3535,Hi3531,Hi3536,Hi3536C,Hi3536D,Hi3518EV200,Hi3518EV201,Hi3520DV200,Hi3516CV200,Hi3516CV300,Hi3516AV200,Hi3520DV300,Hi3519V101,sd3403,hi3519av200

1585

surfaceview

首先是api,结构如下 java.lang.Object    ↳ android.view.View      ↳ android.view.SurfaceView Known Direct Subclasses GLSurfaceView, VideoView videoview是子类,所以可以用me

pipisky2006的专栏 1783

Android 性能之 Game Mode

本文的目的是介绍 AOSP Game Mode 功能。Game Mode 功能的核心是系统服务 GameManagerService,在本文中用 GMS 指代 GameManagerService。在 API 26 之后,应用开发者可以通过将应用的 category 属性设置为 "game",使系统(即 GMS)能够将该应用识别为 "游戏"。GMS 定义了 4 种 game mode,即 1|2|3|4|standard|performance|battery|custom;

专注于系统快稳省领域 3066

Xilinx Aurora 8B/10B IP核详解和仿真

Xilinx Aurora 8b/10b IP核的详解,以及使用与仿真示例,对IP核的配置和如何仿真有非常详细的说明,除了对IP核官方文档的内容进行了解析以外,还对GTX引脚的选择等比较容易混淆和不好理解的地方进行了说明。最后对IP核的仿真运行进行了STEP BY STEP 的说明,对仿真的结果也进行了简要的说明。 该文档对Xilinx FPGA和ZYNQ SOC下 AURORA 8B/10B IP核的使用提供了一个快速上手的指导。

weixin_43354598的博客 1万+

SurfaceView

剖析 SurfaceView ! Callback以及SurfaceHolder!! http://blog.csdn.net/xiaominghimi/archive/2010/12/21/6090575.aspx  callback接口:  只要继承SurfaceView类并实现SurfaceHolder.Callback接口就可以实现一个自定义的SurfaceView了,Sur

GrimRaider的专栏 4274

YOLOv13改进策略【YOLO和Mamba】| 替换骨干 Mamba-YOLOv13-T !!! 最新的发文热点

模块是模型中的一个重要组成部分,其主要作用是在模型的初始阶段对输入图像进行处理,方便后续的特征提取和目标检测。以下是对。

Limiiiing的博客 355

(转)【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理!

李华明Himi 原创,转载务必在明显处注明: 转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/346.html          在这里先向各位童鞋道个歉!我解释下:当我在给大家讲解的时候会附带上源码,可是这个源码是演示代码,为了让大家看的清楚,所以我会尽可能把一些与其无关的删掉,但是发现演示代码还是

gxj1680的专栏 721

网络流量异常信息分析方法研究

本课题针对网络安全中网络流量异常的分析方法进行研究,提出一种基于机器学习和深度学习的异常检测算法。该算法采用卷积神经网络(CNN)和长短时记忆神经网络(LSTM)结合的方式,通过训练得到二分类模型,从而实现对网络流量异常的检测。随着互联网的飞速发展,网络攻击事件日益增多,网络安全问题成为了亟待解决的问题之一。常见的网络攻击手段包括 DDoS 攻击、SQL 注入、XSS 攻击等,这些攻击手段可能导致网络系统发生异常,给网络运维、数据安全带来极大的挑战。

肥晨开发的学习之路 1037

论文阅读 AIED 2024 Coding with AI: How Are Tools Like ChatGPT Being Used by Students in Foundational Pro

该论文题为《Coding with AI: How Are Tools Like ChatGPT Being Used by Students in Foundational Programming Courses》,由美国犹他州立大学的 Aashish Ghimire 与 John Edwards 共同撰写,发表于人工智能与教育领域顶级会议。

CSPhD-winston的博客 308

MySQL数据分析入门:从建库建表到分组查询的完整闭环

在数据驱动决策的背景下,SQL作为操作关系型数据库的标准语言,是从海量数据中提取价值的基础工具。对于初学者而言,直接理解索引、事务等底层原理容易陷入知识碎片化,真正高效的学习路径是从业务问题出发,快速跑通“建库→建表→插入数据→查询统计”的最小闭环。通过掌握SELECT、WHERE、GROUP BY、JOIN等核心语法,你就能将“哪个城市贡献最大”“本月订单量多少”等业务诉求翻译为可执行的查询语句,并借助聚合函数与分组统计获得决策依据。本文以一套可运行的销售数据为例,演示如何完成环境搭建、表结构设计、数据写

weixin_34268753的博客 140

芯片原厂linux驱动开发的分享

大家好,我是XX,来自湖南XX学院,电子信息18级,也曾在创新基地控制组学习过两三年,毕业后就职于一家芯片原厂的解决方案部,担任驱动工程师的职位,算上实习期,我的工作时长已有两年。在此我想将这两年期间学习与积累到的一些经验输出出来,与大家一同分享。知识面有限,只能简单介绍一些驱动开发方向的一些经验,且由于经验尚浅,文中难免会有一些疏漏和错误之处,还请大家积极地批评指正。

嵌入式技术开发 849
上一篇: 【Android游戏开发十八】解放手指,利用传感器开发游戏!(本文讲解在SurfaceView中用重力传感器控制圆球的各方向移动)...
下一篇: 【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理!...
iteye_6921
博客等级 码龄8年 0粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值