OpenGL ES学习之GLSurfaceView的使用讲解
一.glsurfaceview概述
glsurfaceview从android 1.5(api level 3)开始加入,继承自surfaceview,实现了surfaceholder.callback2接口,拥有surfaceview的全部特性,也有view所有的功能和属性,特别是处理事件的能力,它主要是在surfaceview的基础上它加入了egl的管理,并自带了一个glthread绘制线程(eglcontext创建gl环境所在线程即为gl线程),绘制的工作直接通过opengl在绘制线程进行,不会阻塞主线程,绘制的结果输出到surfaceview所提供的surface上,这使得glsurfaceview也拥有了opengles所提供的图形处理能力,通过它定义的render接口,使更改具体的render的行为非常灵活性,只需要将实现了渲染函数的renderer的实现类设置给glsurfaceview即可。
glsurfaceview的特性:
1.管理一个surface,这个surface就是一块特殊的内存,能直接排版到android的视图view上。
2.管理一个egl display,它能让opengl把内容渲染到上述的surface上。
3.用户自定义渲染器(render)。
4.让渲染器在独立的线程里运作,和ui线程分离。
5.支持按需渲染(on-demand)和连续渲染(continuous)。
6.可以封装、跟踪并且排查渲染器的问题。
二.glsurfaceview的基本使用
1.创建glsurfaceview
glsurfaceview一般有两种创建方式:(1)一种是在android布局文件中配置;(2)直接在代码中new出来;
以下是第一种方式:xml文件中配置:
在上面的代码中,因为glsurfaceview本身就是一个view控件,所以是可以直接在xml中添加该控件,然后就可以直接在activity或者fragment中通过id找到该控件并操作它;
以下是通过new的方法直接创建glsurfaceview的实例:
package com.yh.opengltext01; import android.app.activity; import android.app.activitymanager; import android.content.pm.configurationinfo; import android.opengl.glsurfaceview; import android.os.build; import android.os.bundle; import android.widget.toast; public class mainactivity extends activity { private glsurfaceview mglsurfaceview; private boolean mrendererset = false; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); mglsurfaceview = new glsurfaceview(this); final activitymanager activitymanager = (activitymanager) getsystemservice(activity_service); final configurationinfo configurationinfo = activitymanager.getdeviceconfigurationinfo(); final boolean supportses2 = configurationinfo.reqglesversion >= 0x20000 ||(build.version.sdk_int >= build.version_codes.ice_cream_sandwich_mr1) &&(build.fingerprint.startswith("generic")) || build.fingerprint.startswith("unknow") || build.model.contains("google_sdk") || build.model.contains("emulator") || build.model.contains("android sdk built for x86"); if (supportses2){ mglsurfaceview.seteglcontextclientversion(2); mglsurfaceview.setrenderer(new simplerenderer(this)); mrendererset = true; }else { toast.maketext(this , "this device does not support opengl es 2.0." , toast.length_short).show(); return; } setcontentview(mglsurfaceview); } @override protected void onpause() { if (mrendererset){ mglsurfaceview.onpause(); } super.onpause(); } @override protected void onresume() { super.onresume(); if (mrendererset){ mglsurfaceview.onresume(); } } }activity的oncreate方法中首先我们就创建glsurfaceview的实例:
第二步我们判断了当前设备是否支持opengl es2,不支持我们直接retrun,并做相应的提示,后面“||”是为了判断设备是不是模拟器的情况:mglsurfaceview = new glsurfaceview(this);
第三步如果支持,我们为我们glsurfaceview配置一些简单的属性,并为它设置渲染器(render),渲染器我们之后会解释:final boolean supportses2 = configurationinfo.reqglesversion >= 0x20000 ||(build.version.sdk_int >= build.version_codes.ice_cream_sandwich_mr1) &&(build.fingerprint.startswith("generic")) || build.fingerprint.startswith("unknow") || build.model.contains("google_sdk") || build.model.contains("emulator") || build.model.contains("android sdk built for x86");
第四步,把我们glsurfaceview的生命周期和activity的生命周期绑定:mglsurfaceview.seteglcontextclientversion(2); //设置渲染器 mglsurfaceview.setrenderer(new simplerenderer(this));
@override protected void onpause() { if (mrendererset){ mglsurfaceview.onpause(); } super.onpause(); } @override protected void onresume() { if (mrendererset){ mglsurfaceview.onresume(); } super.onresume(); }
以上第二步到最后一步在使用id获取glsurfaceview也是需要这样做的;
这样一个简单初始化glsurfaceview的初始化就做好了;
三.glsurfaceview的事件处理
为了处理事件,一般都是继承glsurfaceview类并重载它的事件方法,但是由于glsurfaceview是多线程的,渲染器在独立的渲染线程里,你应该使用java的跨线程机制跟渲染器通讯,glsurfaceview提供的queueevent(runnable)方法就是一种相对简单的操作,queueevent()方法被安全地用于在ui线程和渲染线程之间进行交流通信:
该方法的原型:
/** * queue a runnable to be run on the gl rendering thread. this can be used * to communicate with the renderer on the rendering thread. * must not be called before a renderer has been set. * @param r the runnable to be run on the gl rendering thread. */ public void queueevent(runnable r) { mglthread.queueevent(r); }
简单的使用:
package com.yh.opengltext01; import android.content.context; import android.opengl.glsurfaceview; import android.util.attributeset; import android.view.keyevent; import android.view.motionevent; public class myglsurfaceview extends glsurfaceview { public myglsurfaceview(context context) { super(context); } public myglsurfaceview(context context, attributeset attrs) { super(context, attrs); } @override public boolean onkeydown(int keycode, keyevent event) { if (keycode == keyevent.keycode_dpad_center) { queueevent(new runnable() { // 这个方法会在渲染线程里被调用 public void run() { //todo 写自己的逻辑 } }); return true; } return super.onkeydown(keycode, event); } @override public boolean ontouchevent(motionevent event) { queueevent(new runnable() { public void run() { //todo 做自己的逻辑 } }); return super.ontouchevent(event); } }
如果在ui线程里调用渲染器的方法,因为ui事件和渲染绘制是在不同的线程里,会收到“call to opengl es api with no current context”的警告,典型的案例就是在键盘或触摸事件方法里直接调用opengl es的api。
以上就是openglsurfaceview的简单使用;
上一篇: 不是说不吃晚饭对身体好么
推荐阅读
-
OpenGL ES学习之GLSurfaceView的使用讲解
-
Android开发学习之控件GridView的使用讲解
-
es6学习笔记之Async函数的使用示例
-
C++ 基础学习之使用有返回值的函数以及函数变体讲解
-
Android Fragment的使用学习之嵌套Fragments (Nested Fragments) 的使用及常见错误讲解
-
Android开发之OpenGL、OpenGL ES的概念和实例讲解
-
Android开发之ExoPlayer的学习和使用(音频)讲解
-
iOS UI入门学习之Objective-C和Swift下UIPageControl的使用讲解
-
es6学习笔记之Async函数的使用示例
-
C++ 基础学习之使用有返回值的函数以及函数变体讲解