落鹤生 发布于 2011-12-13 13:30 点击:次 | 来自:CSDN博客原文 |
Android里面的画图分为2D和3D两种:
Canvas canvas = surfaceHolder.lockCanvas() ;
//取得画图的Canvas
/*---------------------------------画图 **-------------------------------- 画图结束*/ surfaceHolder.unlockCanvasAndPost() ; //提交并显示 至于SurfaceView的使用可参考实例1 所有前面3种方式的 画图的一些例子在SDK上都有,写得也比较清楚,我这里就不说了,这里写一下我调这些代码过程一些小经验,应该主要涉及的是Activity这方面,应该以后都用得到: 首先是关于Eclipse的 : (1) ctrl + shift + O 可以自动添加需要的依赖包,这功能挺实用的觉得,还有alt + /是语法补全 ; (2) 代码中右键比较实用的功能有很多,我记得的是F3找类的声明,F4找类的继承关系 ; (3) 断点调试比较方便的,在Eclipse的右上交可以选择阅读代码的方式,还能经如debug模式,我现在用到的两个打log的方式: Log.e("class", "value : "+ classname) ; //检测class是否为空指针 Log.e(this.getClass().getName(), "notice message") ; 然后是关于Activity的 : (1) 首先尽量把UI的设计放在XML中实现,而不要放在代码中实现,这样方便设计,修改和移植 ; (2) 所有使用到的component都必须在manifest中声明,不然程序中找不到相应的conponet的时候会报错 ; (3) 一般每一个Activity都对应于一个类,和一个相应的布局文件xml ; (4) 每一个Activity只有使用setContentView()绑定内容后才会显示,而且你才能从这个内容(比如xml中)获取到你需要的元素 ; (5) res/drawable和res/raw中的元素的区别是drawable中的元素像素可能会被系统优化,而raw中的不会被优化 ; (6) 当多个Activity都从res/drawable中获得同一个元素,如果其中一个修改它的属性,所有其他的Activity中这个元素的相应属性都会改变 ; (7) res/anim中保存的是动画相关的xml ; 下面我们总结以下2D 画图用到的包 : android.view //画图是在View中进行的 android.view.animation //定义了一些简单的动画效果Tween Animation 和 Frame. Animation android.graphics //定义了画图比较通用的API,比如canvas,paint,bitmap等 android.graphics.drawable //定义了相应的Drawable(可画的东西),比如说BitmapDrawable,PictureDrawable等 android.graphics.drawable.shapes //定义了一些shape 二、了解了2D,我们再来看看3D的 画图方式。3D 画图SDK上讲得很简单,只是提了一个通用的方式,就是继承一个View, 然后在这个View里面获得 Opengl的句柄进行 画图,道理应该来说是和2D一样的,差别就是一个是使用2D的API 画图, 一个是使用3D的。不过因为3D openGl|ES具有一套本身的运行机制,比如渲染的过程控制等, 因此Android为我们提供了一个专门的用在3D 画图上的 GLSurfaceView。 这个类被放在一个单独的包android.opengl里面,其中实现了其他View所不具备的操作: (1) 具有OpenGL|ES调用过程中的错误跟踪,检查工具,这样就方便了Opengl编程过程的debug ; (2) 所有的画图是在一个专门的Surface上进行,这个Surface可以最后被组合到android的View体系中 ; (3) 它可以根据EGL的配置来选择自己的buffer类型,比如RGB565,depth=16 (这里有点疑问, SurfaceHolder的类型是SURFACE_TYPE_GPU,内存就是从EGL分配过来的?) (4) 所有画图的操作都通过render来提供,而且render对Opengl的调用是在一个单独的线程中 (5) Opengl的运行周期与Activity的生命周期可以协调 下面我们再看看利用GLSurface画3D图形的一个典型的Sequence (1) 选择你的EGL配置(就是你 画图需要的buffer类型) [optional] : setEGLConfigChooser(boolean) setEGLConfigChooser(EGLConfigChooser) setEGLConfigChooser(int, int, int, int, int, int) (2) 选择是否需要Debug信息 [optional] : setDebugFlags(int) setGLWrapper(GLSurfaceView.GLWrapper). (3) 为GLSurfaceView注册一个 画图的renderer : setRenderer(GLSurfaceView.Renderer) (4) 设置reander mode,可以为持续渲染或者根据命令来渲染,默认是continuous rendering [optional]: setRenderMode(int) 这里有一个要注意的地方就是必须将Opengl的运行和Activity的生命周期绑定在一起, 也就是说Activity pause的时候,opengl的渲染也必须pause。 另外GLSurfaceView还提供了一个非常实用的线程间交互的函数 queueEvent(Runnable), 可以用在主线程和render线程之间的交互,下面就是SDK提供的范例: class MyGLSurfaceView extends GLSurfaceView { private MyRenderer mMyRenderer; public void start() { mMyRenderer = ...; setRenderer(mMyRenderer); } public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { queueEvent(new Runnable() { // This method will be called on the rendering // thread: public void run() { mMyRenderer.handleDpadCenter(); }}); return true; } return super.onKeyDown(keyCode, event); } } GLSurfaceView是Android提供的一个非常值得学习的类,它实际上是一个如何在View中添加 画图线程的例子,如何在中使用线程的例子,如何添加事件队列的例子,一个使用SurfaceView 画图的经典Sequence,一个如何定义Debug信息的例子,觉得把它看懂了可以学到很多知识,具体的源码在:/framworks/base/opengl/java/android/opengl /GLSurfaceView.java 。 3D的内容基本到这里基本讲完了,剩下的主要是如何使用Opengl API的问题了,可以看看API demo中简单的立方体,复杂的可以看看它那个魔方的实现。下面我们总结一下3D 画图需要用到的包: Android.opengl / /主要定义了GLSurfaceView javax.microedition.khronos.egl //java层的egl接口 javax.microedition.khronos.opengles //opengl API
三、了解了2D和3D基本的
画图方法,我们再回过头来看看整个Android对Opengl和Skia的调用层次关系
3.1、首先来看2D,2D是主要使用的图形引擎,毕竟3D受制于其过高的硬件要求在手机上使用还是比较少,而且Skia也能部分实现类似于3D的效果, 因此可以说SKia实现了Android平台上绝大多数的图形工作。 下面我们来看看从应用层到底层对skia的调用关系: Android对skia的调用是一个比较经典的调用过程,应用程序的几个包是在SDK中提供的; JNI放在框架的JNI目录下面的Graphic目录;skia 是作为一个第三方组件放在external目录下面。我们可以稍微了解一下skia的结构:
这里主要涉及到的3个库:
libcorecg.so 包含/skia/src/core的部分内容,比如其中的Region,Rect是在SurfaceFlinger里面计算可是区域的操作基本单位 libsgl.so 包含/skia/src/core|effects|images|ports|utils的部分和全部内容, 这个实现了skia大部分的图形效果,以及图形格式的编解码 libskiagl.so 包含/skia/src/gl里面的内容,主要用来调用opengl实现部分效果 另外我看到/skia/src中有两个目录animator和view没有写入makefile的编译路径中,我觉得这两个目录是很重要的,不知道是现在Android还没使用到,还是用其他的方式加载进去的。 要想在底层使用skia的接口来 画图需要全面了解skia的一整套机制,实际上skia开源到现在还没多久,在网上能找到的资料是也是很粗浅的,如果将来真需要在这方面下功夫肯定是需要一定的工作量的。 3.2、Android对3D的调用曾经让我迷惑了一段时间,因为在framewoks/base/core/jni这个目录一直没找到跟opengl相 关的内容,后面去仔细看看opengl里面的内容才知道Android把opengl的本地实现,JNI,java接口都放在 /frameworks /base/opengl下面了,而且它内部还带了一个工具可以生成JNI代码。
我们来看看opengl的目录结构:
/include 包含egl和gles所有的头文件 /java/android/opengl 这个目录包含的就是我们3D 画图要使用到的GLSurfaceView /java/com/google/android/gles_jni 这个目录包含一些自动生成的文件 /java/javax/microedition/khronos/egl 这就是应用层使用到的egl接口 /java/javax/microedition/khronos/opengl 这就是应用层使用到的opengl接口 /libagl 这个就是opengl主要的实现了 /libs 这里面包含两个库的实现,一个是libegl.so 还有一个是libGL|ES_CM.so /tools 在我的理解这就是一个jni的生成工具 Opengl编程谁都知道是一个大工程,我觉得现在对3D的需求应该是很低的,很多效果我们使用skia也可以实现。 所以我觉得将来的重点应该还是放在skia上面。 实例1: SurfaceView的使用 package com.gameloft.SurfaceView; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MainView extends SurfaceView implements SurfaceHolder.Callback , Runnable { SurfaceHolder holder; public MainView(Context context) { super(context); holder = this.getHolder(); //获取holder holder.addCallback(this); surfaceHolder.setFormat(PixelFormat.OPAQUE); //surfaceHolder.setFormat(PixelFormat.RGB_565); //surfaceHolder.setFormat(PixelFormat.RGBA_8888); } boolean blRun=true; @Override public void run() { while (blRun) { Canvas canvas = holder.lockCanvas();/ /获取画布 Paint paint = new Paint(); paint.setColor(Color.BLUE); canvas.drawRect(new RectF(40,60,80,80), paint); canvas.drawLine(0,0, 320, 480, paint); holder.unlockCanvasAndPost(canvas) ;//解锁画布,提交画好的图像 System.out.println("run"); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { new Thread(this).start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { blRun=false; } } 注意:surfaceHolder默认的格式 PixelFormat.OPAQUE。 时间上的效率 PixelFormat.OPAQUE最高, PixelFormat.RGB_565略低点, PixelFormat.RGBA_8888则要低很多。 在ALG的demo中: surfaceHolder的格式为PixelFormat.OPAQUE,FPS稳定在帧数38左右。 surfaceHolder的格式为PixelFormat.RGB_565,FPS稳定在帧数37左右。 surfaceHolder的格式为PixelFormat.RGBA_8888,FPS稳定在帧数19左右。 RGBA_8888也太慢了吧 (yili_xie) |