Android之SurfaceView简介(一)

1. SurfaceView介绍

    
    通常情况程序的View和用户响应都是在同一个线程中处理的,这也是为什么处理长时间事件(例如访问网络)需要放到另外的线程中去(防止阻塞当前UI线程的操作和绘制)。但是在其他线程中却不能修改UI元素,例如用后台线程更新自定义View(调用View的在自定义View中的onDraw函数)是不允许的。
 
    如果需要在另外的线程绘制界面、需要迅速的更新界面,或者渲染UI界面需要较长的时间,这种情况就要使用SurfaceView了。SurfaceView中包含一个Surface对象,而Surface是可以在后台线程中绘制的。
    SurfaceView的性质决定了其比较适合一些场景:需要界面迅速更新、对帧率要求较高的情况。
    使用SurfaceView需要注意以下几点情况:
     (1)SurfaceView和SurfaceHolder.Callback函数都从当前SurfaceView窗口线程中调用(一般而言就是程序的主线程)。
     (2)有关资源状态要注意和绘制线程之间的同步。 
     (3)在绘制线程中必须先合法的获取Surface才能开始绘制内容,在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之间的状态为合法的,在Surface类型为SURFACE_TYPE_PUSH_BUFFERS时是不合法的。 
     (4)额外的绘制线程会消耗系统的资源,在使用SurfaceView的时候要注意这点。 
 

2. 使用SurfaceView

    
    只要继承SurfaceView类并实现SurfaceHolder.Callback接口就可以实现一个自定义的SurfaceView了,SurfaceHolder.Callback在底层的Surface状态发生变化的时候通知View,SurfaceHolder.Callback具有如下的接口:
        surfaceCreated(SurfaceHolder holder):当Surface第一次创建后会立即调用该函数。程序可以在该函数中做些和绘制界面相关的初始化工作,一般情况下都是在另外的线程来绘制界面,所以不要在这个函数中绘制Surface。 
       surfaceChanged(SurfaceHolder holder, int format, int width,int height):当Surface的状态(大小和格式)发生变化的时候会调用该函数,在surfaceCreated调用后该函数至少会被调用一次。 
       surfaceDestroyed(SurfaceHolder holder):当Surface被摧毁前会调用该函数,该函数被调用后就不能继续使用Surface了,一般在该函数中来清理使用的资源。 
 
    通过SurfaceView的getHolder()函数可以获取SurfaceHolder对象,Surface 就在SurfaceHolder对象内。虽然Surface保存了当前窗口的像素数据,但是在使用过程中是不直接和Surface打交道的,由SurfaceHolder的Canvas.lockCanvas()或则Canvas.lockCanvas(Rect dirty)函数来获取Canvas对象,通过在Canvas上绘制内容来修改Surface中的数据。如果Surface不可编辑,或者尚未创建调用该函数会返回null,在 unlockCanvas() 和 lockCanvas()中Surface的内容是不缓存的,所以需要完全重绘Surface的内容,为了提高效率只重绘变化的部分则可以调用lockCanvas(Rect dirty)函数来指定一个dirty区域,这样该区域外的内容会缓存起来。在调用lockCanvas函数获取Canvas后,SurfaceView会获取Surface的一个同步锁直到调用unlockCanvasAndPost(Canvas canvas)函数才释放该锁,这里的同步机制保证在Surface绘制过程中不会被改变(被摧毁、修改)。
    当在Canvas中绘制完成后,调用函数unlockCanvasAndPost(Canvas canvas)来通知系统Surface已经绘制完成,这样系统会把绘制完的内容显示出来。为了充分利用不同平台的资源,发挥平台的最优效果可以通过SurfaceHolder的setType函数来设置绘制的类型,目前接收如下的参数:
        SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface 
        SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface 
        SURFACE_TYPE_GPU:适用于GPU加速的Surface 
        SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。

    注意:一个SurfaceView只在SurfaceHolder.Callback.surfaceCreated() 和 SurfaceHolder.Callback.surfaceDestroyed()调用之间是可用的,其他时间是得不到它的Canvas对象的(null)。


3. SurfaceView和View的区别

    

    SurfaceView和View最本质的区别在于,surfaceView是在一个新起的单独线程中可以重新绘制画面,而View必须在UI的主线程中更新画面。

    在UI的主线程中更新画面可能会引发问题,比如你更新画面的时间过长,那么你的主UI线程会被你正在画的函数阻塞。那么将无法响应按键,触屏等消息。当使用SurfaceView时,由于是在新的线程中更新画面所以不会阻塞UI主线程。但这也带来了另外一个问题,就是事件同步。比如你触屏了一下,你需要SurfaceView中的Thread处理,一般就需要有一个event queue的设计来保存touch event,这会稍稍复杂一点,因为涉及到线程同步。

    所以基于以上,根据游戏特点,一般分成两类:
(1)被动更新画面的。比如棋类,用View就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为在这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
(2)主动更新画面的。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞UI主线程。所以显然view不合适,需要surfaceView来控制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/294027.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 值得永久收藏的WPF项目实战(经典)

01—简介之前也写过好多篇CM框架相关的项目实战文章,比如:C# WPF框架Caliburn.Micro快速搭建C# WPF框架Caliburn.Micro入门实例1C# WPF MVVM项目实战(进阶①)C# WPF MVVM项目实战(进阶②)C# WPF MVVM模式下在主窗体显示子窗体并获取结果C# WPF Caliburn.…

InfoQ十周年:不忘初心,继续前行

我们都知道:软件正在改变世界,也已经看到了在加快这种变化时,于软件世界中我们的影响力。在这种热情下,10年前我们带着一些不寻常的信念与情怀创建了InfoQ:\\\\t我们相信:这个社区需要的内容是开发者所撰写…

eclipse_中的注释_快捷键

eclipse 中的注释 快捷键 把要注释的代码选中,按CtrlShift/ /* */ 形式的 ctrl/ //形式的 取消代码注释: 把要注释的代码选中,按CtrlShift\ /* */ 形式的 ctrl/ //形式的 (1)CtrlSpace 说明:内容助理。提供对方法,变量,参数,j…

html自动填充高度,html元素如何仅使用css填充剩余屏幕高度的100%?

html元素如何仅使用css填充剩余屏幕高度的100%?我有一个标题元素和一个内容元素:#header#content我希望标题具有固定的高度,并且内容可以填满屏幕上可用的所有剩余高度,使用overflow-y: scroll;。这可能没有Javascript…

Android之bitmap压缩的几种方法的解读

转载:http://blog.csdn.net/chzphoenix/article/details/30242315?utm_sourcetuicool&utm_mediumreferral 最近在研究微信的sdk,在缩略图这遇到了一点问题。 微信的缩略图要求是不大于32k,这就需要对我的图片进行压缩。试了几种方法&a…

如何通过 C# kill 指定进程?

咨询区 robr我用代码动态的打开了一个 IE 进程,参考如下代码:static void Main(string[] args){ProcessStartInfo startInfo new ProcessStartInfo("iexplore.exe");startInfo.WindowStyle ProcessWindowStyle.Hidden;startInfo.Arguments …

[转]面向接口编程详解(一)——思想基础

我想,对于各位使用面向对象编程语言的程序员来说,“接口”这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,…

bootstrap模态框

bootsrtap模态框不可叠加使用,点击提交时需要确认,暂时未解决转载于:https://www.cnblogs.com/witchgogogo/p/5550338.html

Oracle 在 多个Virtualbox 虚拟机间 跨不同物理宿主机进行通信

因为单位网络管理的原因,不太方便使用 Virtualbox 的Bridge Adapter 模式,故此欲采用NAT模式,不对外不暴露虚拟机IP。 但是此时会有一个问题:采用NAT模式后,在通常情况下, 从外面看,或者从物理机…

Android之解决在非Activity中使用startActivity

今天遇到一个问题就是,如何在非activity里面使用startActivity(); 解决办法如下、 需要我们有context intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent);

亚马逊 html代码转换,亚马逊七种产品描述常用HTML代码,文字颜色代码让Listing更出彩...

排版风格和排版水平对于亚马逊Listing的运营至关重要。虽说亚马逊以产品为王,但如果消费者打开的是一篇毫无美感的排版,视觉体验不舒服,获取不到吸引他的卖点,转化率将大大降低!没使用HTML代码的卖家,产品描…

如何将自定义的 Delegate 转成 Func 委托?

咨询区 AndreyAkinshin场景是这样的&#xff0c;我自定义了一个 SomeDelegate 委托&#xff0c;然后将 Inc 方法灌入到其中&#xff0c;同时我也将 Inc 赋值给了 Func<int,int> 委托&#xff0c;参考代码如下&#xff1a;class Program{static void Main(string[] args){…

java 文件上传至oracle blob字段 实现

2019独角兽企业重金招聘Python工程师标准>>> 指定文件夹下的所有文件上传至oracle的blob字段&#xff0c;java实现 package com.huth;import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.FileInputStream; i…

基于DDD的.NET开发框架 - ABP工作单元(Unit of Work)

返回ABP系列 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。 ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点&#xff0c;它旨在成为一个通用的WEB应用程序框架和项目模板。 ABP的官方网站&#xff1a;http://www.aspnetboilerp…

中国这门失传已久的武林绝学,竟让研究它的老外拿了诺贝尔奖

全世界只有3.14 % 的人关注了爆炸吧知识欲练神功学好物理中国武术&#xff0c;博大精深。能够掌握一门武林绝学&#xff0c;是全世界男人的终极梦想。可翻翻公认的武林十大绝学&#xff1a;葵花宝典、六脉神剑、九阳神功....不是断子绝孙&#xff0c;就是杀人于无形&#xff0c…

中国地区三级联动下拉菜单的实现

1.首先是js文件(area.js)&#xff1a; 1 function Dsy()2 {3 this.Items {};4 }5 Dsy.prototype.add function(id,iArray)6 {7 this.Items[id] iArray;8 }9 Dsy.prototype.Exists function(id)10 {11 if(typeof(this.Items[id]) "undefined") return false;12 r…

Java里面的arraycopy总结

当我们需要两个数组之和建立一个新的数组的时候&#xff0c;我以为数组也像字符串一样&#xff0c;相加就可以&#xff0c;错了&#xff0c;需要用到arraycopy arraycopy(被复制的数组, 从第几个元素开始复制, 要复制到的数组, 从第几个元素开始粘贴, 一共需要复制的元素个数);…

C#的dapper使用

Dapper是.NET下一个micro的ORM&#xff0c;它和Entity Framework或Nhibnate不同&#xff0c;属于轻量级的&#xff0c;并且是半自动的。Dapper只有一个代码文件&#xff0c;完全开源&#xff0c;你可以放在项目里的任何位置&#xff0c;来实现数据到对象的ORM操作&#xff0c;体…