台州建设质量监督网站,中国建设银行山西分行招聘网站,做外贸用什么视频网站好,集和品牌设计公司官网1. 什么是surfaceview surfaceview内部机制和外部层次结构
在安卓开发中#xff0c;我们经常会遇到一些需要高性能、高帧率、高画质的应用场景#xff0c;例如视频播放、游戏开发、相机预览等。这些场景中#xff0c;我们需要直接操作图像数据#xff0c;并且实时地显示到…1. 什么是surfaceview surfaceview内部机制和外部层次结构
在安卓开发中我们经常会遇到一些需要高性能、高帧率、高画质的应用场景例如视频播放、游戏开发、相机预览等。这些场景中我们需要直接操作图像数据并且实时地显示到屏幕上。如果我们使用普通的view组件来实现这些功能可能会遇到以下问题
view组件是在主线程中进行绘制的如果绘制过程耗时过长或者频繁刷新可能会导致主线程阻塞影响用户交互和界面响应。view组件在绘制时没有使用双缓冲机制也就是说每次绘制都是直接在屏幕上进行的这可能会导致绘制过程中出现闪烁或者撕裂的现象。view组件是基于view层次结构的也就是说每个view都是一个矩形区域如果我们想要实现一些不规则形状或者透明度变化的效果可能会比较困难。
为了解决这些问题安卓提供了一种特殊的view组件surfaceview 。surfaceview拥有自己独立的surface也就是一个可以在其上直接绘制内容的图形缓冲区。surfaceview的内容是透明的可以嵌入到view层次结构中并且可以和其他view进行重叠或者裁剪。surfaceview适用于需要频繁刷新或处理逻辑复杂的绘图场景如视频播放、游戏等。
下图展示了surfaceview和普通view在屏幕上的显示效果 surfaceview和普通view
从图中可以看出普通view是按照顺序依次绘制到屏幕上的而surfaceview则是直接绘制到屏幕上的一个透明区域并且可以和其他view进行重叠或者裁剪。
2. surfaceview和view的区别
从上面的介绍中我们已经了解了surfaceview和普通view在显示效果上的区别。那么在实现原理和使用方式上它们又有什么不同呢下面我们来对比一下它们的主要区别
特点普通viewsurfaceview更新方式主动更新可以在任何时候调用invalidate方法来触发重绘在onDraw方法中使用canvas进行绘制被动更新不能直接控制重绘需要通过一个子线程来进行页面的刷新在子线程中直接操作surface进行绘制刷新线程主线程刷新可以保证界面的一致性和同步性但是可能导致主线程阻塞或者掉帧子线程刷新可以避免主线程阻塞并且可以提高刷新频率和效率但是需要注意线程间的通信和同步问题缓冲机制无双缓冲机制每次绘制都是直接在屏幕上进行可以节省内存空间但是可能导致闪烁或者撕裂的现象有双缓冲机制每次绘制都是先在一个缓冲区中进行然后再将缓冲区中的内容复制到屏幕上可以避免闪烁或者撕裂的现象并且可以提高绘制质量但是需要消耗更多的内存空间
更新方式普通view适用于主动更新的情况也就是说我们可以在任何时候调用view的invalidate方法来触发view的重绘然后在onDraw方法中使用canvas进行绘制。而surfaceview主要用于被动更新的情况也就是说我们不能直接控制surfaceview的重绘而是需要通过一个子线程来进行页面的刷新然后在子线程中直接操作surface进行绘制。刷新线程普通view是在主线程里面进行刷新的也就是说所有的绘制操作都是在主线程中完成的。这样的好处是可以保证界面的一致性和同步性但是也有可能导致主线程阻塞或者掉帧。而surfaceview是通过一个子线程来进行页面的刷新的也就是说所有的绘制操作都是在子线程中完成的。这样的好处是可以避免主线程阻塞并且可以提高刷新频率和效率但是也需要注意线程间的通信和同步问题。缓冲机制普通view在绘图时没有使用双缓冲机制也就是说每次绘制都是直接在屏幕上进行的。这样的好处是可以节省内存空间但是也可能导致绘制过程中出现闪烁或者撕裂的现象。而surfaceview在底层实现机制中已经实现了双缓冲机制也就是说每次绘制都是先在一个缓冲区中进行然后再将缓冲区中的内容复制到屏幕上。这样的好处是可以避免闪烁或者撕裂的现象并且可以提高绘制质量但是也需要消耗更多的内存空间。
3. surfaceview的创建和使用
了解了surfaceview和普通view的区别之后我们就可以开始创建和使用surfaceview了。创建自定义的surfaceview需要以下几个步骤
继承surfaceview首先我们需要创建一个自定义的类继承自surfaceview并实现两个接口surfaceholder.callback和runnable。前者用于监听surface的状态变化后者用于实现子线程的逻辑。初始化surfaceholder其次我们需要在构造方法中初始化surfaceholder对象并注册surfaceholder的回调方法。surfaceholder是一个用于管理surface的类它提供了一些方法来获取和操作surface。处理回调方法然后我们需要在回调方法中处理surface的创建、改变和销毁事件。当surface被创建时我们需要启动子线程并根据需要调整view的大小或位置当surface被改变时我们需要重新获取surface的宽高并根据需要调整view的大小或位置当surface被销毁时我们需要停止子线程并释放相关资源。实现run方法接着我们需要在run方法中实现子线程的绘图逻辑。我们可以使用一个循环来不断地刷新页面并且根据不同的条件来控制循环的退出。获取canvas对象最后我们需要在draw方法中获取canvas对象并通过lockcanvas和unlockcanvasandpost方法进行绘图操作。lockcanvas方法会返回一个canvas对象我们可以使用它来对surface进行绘制unlockcanvasandpost方法会将绘制好的内容显示到屏幕上并且释放canvas对象。
下面给出一个简单的示例代码实现了一个简单的画板功能
//自定义类继承自SurfaceView并实现SurfaceHolder.Callback和Runnable接口
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {//声明SurfaceHolder对象private SurfaceHolder mHolder;//声明子线程对象private Thread mThread;//声明画笔对象private Paint mPaint;//声明画布对象private Canvas mCanvas;//声明一个标志位用于控制子线程的退出private boolean mIsDrawing;//构造方法初始化相关对象public MySurfaceView(Context context) {super(context);//获取SurfaceHolder对象mHolder getHolder();//注册SurfaceHolder的回调方法mHolder.addCallback(this);//初始化画笔对象设置颜色和宽度mPaint new Paint();mPaint.setColor(Color.RED);mPaint.setStrokeWidth(10);}//当Surface被创建时启动子线程并根据需要调整View的大小或位置Overridepublic void surfaceCreated(SurfaceHolder holder) {//设置标志位为true表示子线程可以开始运行mIsDrawing true;//创建并启动子线程mThread new Thread(this);mThread.start();}//当Surface被改变时重新获取Surface的宽高并根据需要调整View的大小或位置Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {//TODO: 根据需要调整View的大小或位置}//当Surface被销毁时停止子线程并释放相关资源Overridepublic void surfaceDestroyed(SurfaceHolder holder) {//设置标志位为false表示子线程可以停止运行mIsDrawing false;try {//等待子线程结束并释放子线程对象mThread.join();mThread null;} catch (InterruptedException e) {e.printStackTrace();}}//实现run方法实现子线程的绘图逻辑Overridepublic void run() {//使用一个循环来不断地刷新页面while (mIsDrawing) {//获取当前时间用于计算绘制时间long start System.currentTimeMillis();//调用draw方法进行绘制操作draw();//获取结束时间用于计算绘制时间long end System.currentTimeMillis();//如果绘制时间小于16ms则延时一段时间保证每秒60帧的刷新率if (end - start 16) {try {Thread.sleep(16 - (end - start));} catch (InterruptedException e) {e.printStackTrace();}}}}//获取canvas对象并通过lockCanvas和unlockCanvasAndPost方法进行绘制操作private void draw() {try {//通过lockCanvas方法获取canvas对象如果surface不可用则返回nullmCanvas mHolder.lockCanvas();if (mCanvas ! null) {//TODO: 在canvas上进行绘制操作例如画线、画圆、画文字等//在本例中我们简单地使用随机数生成一些坐标点并用画笔连接它们形成一条折线图//生成一个随机数对象Random random new Random();//生成一个点的集合用于存储坐标点ListPoint points new ArrayList();//循环生成10个随机坐标点并添加到集合中for (int i 0; i 10; i) {int x random.nextInt(mCanvas.getWidth());int y random.nextInt(mCanvas.getHeight());points.add(new Point(x, y));}//遍历点的集合用画笔连接相邻的两个点形成一条折线图for (int i 0; i points.size() - 1; i) {Point p1 points.get(i);Point p2 points.get(i 1);mCanvas.drawLine(p1.x, p1.y, p2.x, p2.y, mPaint);}//通过unlockCanvasAndPost方法将绘制好的内容显示到屏幕上并释放canvas对象mHolder.unlockCanvasAndPost(mCanvas);}} catch (Exception e) {e.printStackTrace();}}
}
下图展示了上述代码运行的效果 简单的画板
从图中可以看出我们在surface上绘制了一条随机的折线图并且显示到了屏幕上。这只是一个简单的示例我们可以根据自己的需求实现更复杂的绘图逻辑和效果。
4. surfaceview和activity的生命周期
在使用surfaceview时我们需要注意它和activity的生命周期之间的关系。因为surfaceview是嵌入到view层次结构中的所以它会受到activity的生命周期的影响。但是surfaceview也有自己的生命周期它是由surfaceholder来管理的。因此对于具有surfaceview的activity存在两个单独但相互依赖的状态机应用oncreate/onresume/onpause和已创建/更改/销毁的surface。
下图展示了这两个状态机之间的关系 surfaceview和activity的状态机之间的关系 surfaceview和activity的生命周期
从图中可以看出当activity被创建时会触发surfaceview的创建当activity被恢复时会触发surfaceview的改变当activity被暂停时会触发surfaceview的销毁。因此在这些事件中我们需要做一些相应的处理例如
启动/停止子线程当surface被创建或者销毁时我们需要启动或者停止子线程并根据需要调整view的大小或位置。如果我们不及时地启动或者停止子线程可能会导致内存泄漏或者空指针异常。保存/恢复状态当activity被暂停时我们需要从子线程中提取状态并保存到bundle中当activity被恢复时我们需要从bundle中恢复状态并传递给子线程。如果我们不及时地保存或者恢复状态可能会导致数据丢失或者不一致。
5. surfaceview和glsurfaceview
在上面的内容中我们介绍了如何使用surfaceview来实现一些高性能、高帧率、高画质的应用。但是如果我们想要实现一些更加复杂和精美的3D图形效果例如光照、阴影、纹理、动画等那么我们就需要使用opengl es来进行渲染。opengl es是一种跨平台的图形库它可以利用gpu加速来提高渲染效率。
为了方便我们使用opengl es进行渲染安卓提供了一种专门用于渲染opengl es内容的surfaceviewglsurfaceview 。glsurfaceview是一种继承自surfaceview的组件它在底层封装了egl上下文、线程间通信以及与activity生命周期交互等功能。使用glsurfaceview时我们无需自己创建和管理子线程只需实现glsurfaceview.renderer接口并设置给glsurfaceview对象即可。
下图展示了glsurfaceview和普通surfaceview在屏幕上的显示效果 glsurfaceview和普通surfaceview
从图中可以看出glsurfaceview和普通surfaceview都是直接绘制到屏幕上的一个透明区域但是glsurfaceview可以使用opengl es来绘制一些更加复杂和精美的3D图形效果。
6. glsurfaceview的创建和使用
了解了glsurfaceview和普通surfaceview的区别之后我们就可以开始创建和使用glsurfaceview了。创建自定义的glsurfaceview需要以下几个步骤
继承glsurfaceview首先我们需要创建一个自定义的类继承自glsurfaceview并在构造方法中初始化相关对象。设置渲染器其次我们需要实现glsurfaceview.renderer接口并设置给glsurfaceview对象。渲染器是一个用于绘制opengl es内容的类它提供了三个方法onSurfaceCreated、onSurfaceChanged和onDrawFrame。设置渲染模式然后我们需要设置glsurfaceview的渲染模式有两种可选RENDERMODE_CONTINUOUSLY和RENDERMODE_WHEN_DIRTY。前者表示持续地刷新页面后者表示只有在调用requestRender方法时才刷新页面。获取opengl es对象最后我们需要在渲染器的方法中获取opengl es对象并使用它来进行绘制操作。opengl es对象是一个用于操作图形数据的类它提供了一系列的方法来创建、加载、绘制、变换、释放等图形资源。
下面给出一个简单的示例代码实现了一个简单的3D立方体效果
//自定义类继承自GLSurfaceView并在构造方法中初始化相关对象
public class MyGLSurfaceView extends GLSurfaceView {//声明渲染器对象private MyRenderer mRenderer;//构造方法初始化相关对象public MyGLSurfaceView(Context context) {super(context);//设置opengl es版本为2.0setEGLContextClientVersion(2);//创建并设置渲染器对象mRenderer new MyRenderer();setRenderer(mRenderer);//设置渲染模式为持续刷新setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);}//自定义类实现GLSurfaceView.Renderer接口并实现三个方法private class MyRenderer implements GLSurfaceView.Renderer {//声明opengl es对象private GLES20 gl;//声明顶点着色器代码private final String vertexShaderCode attribute vec4 vPosition; uniform mat4 uMVPMatrix; void main() { gl_Position uMVPMatrix * vPosition; };//声明片元着色器代码private final String fragmentShaderCode precision mediump float; uniform vec4 vColor; void main() { gl_FragColor vColor; };//声明顶点坐标数组private final float[] vertexCoords {-0.5f, -0.5f, -0.5f, // front bottom left0.5f, -0.5f, -0.5f, // front bottom right0.5f, 0.5f, -0.5f, // front top right-0.5f, 0.5f, -0.5f, // front top left-0.5f, -0.5f, 0.5f, // back bottom left0.5f, -0.5f, 0.5f, // back bottom right0.5f, 0.5f, 0.5f, // back top right-0.5f, 0.5f, 0.5f // back top left};//声明顶点索引数组private final short[] drawOrder {0, 1, 2, // front face0, 2, 3,4, 5, 6, // back face4, 6, 7,0, 4, 7, // left face0, 7, 3,1, 5, 6, // right face1, 6, 2,3, 2, 6, // top face3, 6, 7,0, 1, 5, // bottom face0, 5, 4};//声明颜色数组private final float[] colors {1.0f, 0.0f, 0.0f, 1.0f, // red0.0f, 1.0f, 0.0f, 1.0f, // green0.0f, 0.0f, 1.0f, 1.0f, // blue1.0f, 1.0f, 0.0f, 1.0f, // yellow1.0f, 0.0f, 1.0f, 1.0f, // magenta0.0f, 1.0f, 1.0f, 1.0f // cyan};//声明顶点缓冲对象private FloatBuffer vertexBuffer;//声明索引缓冲对象private ShortBuffer drawListBuffer;//声明颜色缓冲对象private FloatBuffer colorBuffer;//声明顶点着色器对象private int vertexShader;//声明片元着色器对象private int fragmentShader;//声明程序对象private int program;//声明顶点位置属性的句柄private int positionHandle;//声明颜色属性的句柄private int colorHandle;//声明投影矩阵属性的句柄private int mvpMatrixHandle;//声明模型矩阵对象private float[] modelMatrix new float[16];//声明视图矩阵对象private float[] viewMatrix new float[16];//声明投影矩阵对象private float[] projectionMatrix new float[16];//声明模型视图投影矩阵对象private float[] mvpMatrix new float[16];//当Surface被创建时初始化opengl es对象并加载和编译着色器创建和绑定图形数据设置相机位置和投影方式等操作Overridepublic void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {//获取opengl es对象用于后续的绘制操作gl (GLES20) gl10;//设置背景颜色为黑色用于清除屏幕时使用gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//加载和编译顶点着色器返回一个句柄用于后续的链接操作vertexShader loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);//加载和编译片元着色器返回一个句柄用于后续的链接操作fragmentShader loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);//创建一个空的程序对象返回一个句柄用于后续的链接操作program GLES20.glCreateProgram();//将顶点着色器和片元着色器附加到程序对象上GLES20.glAttachShader(program, vertexShader);GLES20.glAttachShader(program, fragmentShader);//链接程序对象生成最终的可执行程序GLES20.glLinkProgram(program);//使用程序对象激活相关的属性和统一变量GLES20.glUseProgram(program);//获取顶点位置属性的句柄用于后续的绑定操作positionHandle GLES20.glGetAttribLocation(program, vPosition);//获取颜色属性的句柄用于后续的绑定操作colorHandle GLES20.glGetUniformLocation(program, vColor);//获取投影矩阵属性的句柄用于后续的绑定操作mvpMatrixHandle GLES20.glGetUniformLocation(program, uMVPMatrix);//将顶点坐标数组转换为字节缓冲对象用于后续的传输操作ByteBuffer bb ByteBuffer.allocateDirect(vertexCoords.length * 4);bb.order(ByteOrder.nativeOrder());vertexBuffer bb.asFloatBuffer();vertexBuffer.put(vertexCoords);vertexBuffer.position(0);//将顶点索引数组转换为字节缓冲对象用于后续的传输操作ByteBuffer dlb ByteBuffer.allocateDirect(drawOrder.length * 2);dlb.order(ByteOrder.nativeOrder());drawListBuffer dlb.asShortBuffer();drawListBuffer.put(drawOrder);drawListBuffer.position(0);//将颜色数组转换为字节缓冲对象用于后续的传输操作ByteBuffer cb ByteBuffer.allocateDirect(colors.length * 4);cb.order(ByteOrder.nativeOrder());colorBuffer cb.asFloatBuffer();colorBuffer.put(colors);colorBuffer.position(0);//设置相机位置和朝向生成视图矩阵Matrix.setLookAtM(viewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);}//当Surface被改变时调整视口大小并设置投影方式生成投影矩阵Overridepublic void onSurfaceChanged(GL10 gl10, int width, int height) {//设置视口大小为Surface的大小GLES20.glViewport(0, 0, width, height);//设置投影方式为透视投影并根据视口宽高比计算投影矩阵float ratio (float) width / height;Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);}//当Surface被绘制时清除屏幕并旋转模型矩阵生成模型视图投影矩阵并传输和绘制图形数据Overridepublic void onDrawFrame(GL10 gl10) {//清除屏幕颜色缓冲区GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);//设置模型矩阵为单位矩阵并根据系统时间旋转模型矩阵Matrix.setIdentityM(modelMatrix, 0);Matrix.rotateM(modelMatrix, 0, (float) SystemClock.uptimeMillis() / 1000 * 30f, 1.0f, 1.0f, 1.0f);//将模型矩阵、视图矩阵和投影矩阵相乘生成模型视图投影矩阵Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modelMatrix, 0);Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvpMatrix, 0);//将模型视图投影矩阵传输到顶点着色器中并激活该属性GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0);//将顶点坐标数据传输到顶点着色器中并激活该属性GLES20.glVertexAttribPointer(positionHandle, 3,GLES20.GL_FLOAT, false,0, vertexBuffer);GLES20.glEnableVertexAttribArray(positionHandle);//使用循环为每个面设置不同的颜色并绘制三角形for (int i 0; i 6; i) {//将颜色数据传输到片元着色器中并激活该属性colorBuffer.position(i * 4);GLES20.glUniform4fv(colorHandle, 1, colorBuffer);//绘制三角形使用顶点索引数组来确定顶点的顺序drawListBuffer.position(i * 6);GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6,GLES20.GL_UNSIGNED_SHORT, drawListBuffer);}}//定义一个加载和编译着色器的方法接收一个着色器类型和一个着色器代码返回一个着色器句柄public int loadShader(int type, String shaderCode) {//创建一个空的着色器对象返回一个句柄用于后续的编译操作int shader GLES20.glCreateShader(type);//将着色器代码传输到着色器对象中GLES20.glShaderSource(shader, shaderCode);//编译着色器对象GLES20.glCompileShader(shader);//返回着色器句柄return shader;}}
}
glsurfaceview的使用方式
什么是glsurfaceview
glsurfaceview是一种专门用于渲染opengl es内容的surfaceview。opengl es是一种用于嵌入式设备上的3D图形渲染API。glsurfaceview类提供了用于管理egl上下文、在线程间通信以及与activity生命周期交互的辅助程序类。使用glsurfaceview时无需自己创建和管理子线程只需实现glsurfaceview.renderer接口并设置给glsurfaceview对象即可。
glsurfaceview和surfaceview的区别
glsurfaceview和surfaceview都是继承自surfaceview的类都可以在子线程中直接操作surface进行绘制。但是glsurfaceview相比surfaceview有以下的优势
glsurfaceview可以自动创建和管理egl上下文无需自己处理egl的初始化、销毁、切换等操作。glsurfaceview可以自动创建和管理子线程无需自己处理线程的启动、停止、同步等操作。glsurfaceview可以自动处理与activity生命周期的交互无需自己处理activity的暂停、恢复、保存状态等操作。glsurfaceview可以提供多种渲染模式可以根据需要调整渲染频率避免过度绘制或掉帧。
glsurfaceview的创建和使用
创建自定义的glsurfaceview继承glsurfaceview并在构造方法中设置opengl es版本、渲染器对象和渲染模式。创建自定义的渲染器实现glsurfaceview.renderer接口并在回调方法中进行初始化、视口设置和绘图操作。
以下是一个简单的示例代码 // 自定义的glsurfaceview类
public class MyGLSurfaceView extends GLSurfaceView {// 构造方法public MyGLSurfaceView(Context context) {super(context);// 设置opengl es版本为2.0setEGLContextClientVersion(2);// 设置渲染器对象setRenderer(new MyRenderer());// 设置渲染模式为连续模式setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);}// 自定义的渲染器类private class MyRenderer implements GLSurfaceView.Renderer {// 渲染器创建时的回调方法Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// 在这里进行一些初始化操作比如设置清屏颜色为黑色GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);}// 渲染器改变时的回调方法Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {// 在这里进行一些视口设置操作比如设置视口大小为surface的大小GLES20.glViewport(0, 0, width, height);}// 渲染器绘制时的回调方法Overridepublic void onDrawFrame(GL10 gl) {// 在这里进行一些绘图操作比如清屏GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);}}
}glsurfaceview和activity的生命周期
当使用glsurfaceview时无需自己处理与activity生命周期的交互glsurfaceview会自动根据activity的状态来暂停或恢复渲染器。但是如果需要保存或恢复一些重要的数据或状态可以在activity的onSaveInstanceState和onRestoreInstanceState方法中进行操作。
以下是一个示意图展示了glsurfaceview和activity的生命周期之间的关系 glsurfaceview和activity的生命周期
从图中可以看出当activity创建时会触发glsurfaceview的onSurfaceCreated回调方法这时会创建渲染器对象并调用渲染器的onSurfaceCreated回调方法。当activity恢复时会触发glsurfaceview的onDrawFrame回调方法这时会恢复渲染器的绘制操作并调用渲染器的onDrawFrame回调方法。当activity暂停时会触发glsurfaceview的onDrawFrame回调方法这时会暂停渲染器的绘制操作并调用渲染器的onDrawFrame回调方法。当activity销毁时会触发glsurfaceview的onSurfaceCreated回调方法这时会销毁渲染器对象并调用渲染器的onSurfaceCreated回调方法。
在这个过程中需要注意以下几点
在activity的onSaveInstanceState和onRestoreInstanceState方法中可以保存或恢复一些重要的数据或状态比如使用一个bundle对象来存储或获取一些opengl es相关的对象或参数。在glsurfaceview的onSurfaceChanged回调方法中可以根据surface的宽高调整视口大小或投影方式比如使用glviewport或glfrustum等方法来设置视口或投影矩阵。在glsurfaceview的setRenderMode方法中可以设置不同的渲染模式比如使用RENDERMODE_CONTINUOUSLY或RENDERMODE_WHEN_DIRTY来设置连续模式或按需模式。