android GLSurfaceView渲染模式

2023-12-22 10:08

本文主要是介绍android GLSurfaceView渲染模式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

GLSurfaceView的渲染模式。


OpenGl ES关于渲染方式有以下两种:RENDERMODE_CONTINUOUSLY和RENDERMODE_WHEN_DIRTY。

默认渲染方式为RENDERMODE_CONTINUOUSLY,当设置为RENDERMODE_CONTINUOUSLY时渲染器会不停地渲染场景,当设置为RENDERMODE_WHEN_DIRTY时只有在创建和调用requestRender()时才会刷新。

一般设置为RENDERMODE_WHEN_DIRTY方式,这样不会让CPU一直处于高速运转状态,提高手机电池使用时间和软件整体性能。


接着简单写一个OpenGL ES程序。

1.在Manifest中添加声明
  为了使用OpenGL ES 2.0 API,需要添加如下声明:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />
 

  OpenGL ES 2.0 requires Android 2.2 (API Level 8) or higher,所以需要确认系统版本。

 

2.创建Activity
  在Activity的布局中,需要加入GLSurfaceView来放置绘制的图形。

  一个最简单的版本如下:


public class OpenGLES20 extends Activity {

    private GLSurfaceView mGLView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        mGLView = new MyGLSurfaceView(this);
        setContentView(mGLView);
    }
}

 

3.创建GLSurfaceView
  GLSurfaceView是一个特殊的组件,你可以在其中绘制OpenGL ES图形。

  你需要扩展这个类,在它的构造方法中设置渲染器:


class MyGLSurfaceView extends GLSurfaceView {

    public MyGLSurfaceView(Context context){
        super(context);

        // Set the Renderer for drawing on the GLSurfaceView
        setRenderer(new MyRenderer());
    }
}

 如果使用OpenGL ES 2.0,还需要加一句声明:

// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2);
 

  还有一个可选的设置是,把渲染模式改为 GLSurfaceView.RENDERMODE_WHEN_DIRTY ,这样仅在你的数据有变化时重新进行渲染。

// Render the view only when there is a change in the drawing data
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
 

  除非你调用requestRender(),这个设置会阻止帧被重画,有些情况下这样效率更高。

 

4.建立一个Renderer类
  Renderer类(渲染器类),即 GLSurfaceView.Renderer的实现类,它控制了与它相关联的 GLSurfaceView 上绘制什么。

  其中有三个主要的回调方法:

onSurfaceCreated() - Called once to set up the view's OpenGL ES environment.
onDrawFrame() - Called for each redraw of the view.
onSurfaceChanged() - Called if the geometry of the view changes, for example when the device's screen orientation changes.


  

  一个简单的实现例子:


public class MyGL20Renderer implements GLSurfaceView.Renderer {

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        // Set the background frame color
        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    }

    public void onDrawFrame(GL10 unused) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }
}

 

 

程序例子
  一个简单的程序例子,并没有绘制什么,只是设置了背景色,为了展示方便,GLSurfaceView类和渲染器类都作为Acitivity的内部类写出。

  首先在Manifest中加上声明:

 

Manifest

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloopengles"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".HelloOpenGLESActivity"
            android:label="@string/title_activity_hello_open_gles" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

Activity

package com.example.helloopengles;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.util.Log;

public class HelloOpenGLESActivity extends Activity
{
    private GLSurfaceView mGLView;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Create a GLSurfaceView instance and set it
        // as the ContentView for this Activity.
        mGLView = new MyGLSurfaceView(this);
        setContentView(mGLView);

    }

    class MyGLSurfaceView extends GLSurfaceView
    {

        public MyGLSurfaceView(Context context)
        {
            super(context);

            try
            {
                // Create an OpenGL ES 2.0 context
                setEGLContextClientVersion(2);

                // Set the Renderer for drawing on the GLSurfaceView
                setRenderer(new MyRenderer());

                // Render the view only when there is a change in the drawing
                // data
                setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

                // 注意上面语句的顺序,反了可能会出错

            }
            catch (Exception e)
            {
                e.printStackTrace();

            }

        }
    }

    public class MyRenderer implements GLSurfaceView.Renderer
    {

        public void onSurfaceCreated(GL10 unused, EGLConfig config)
        {
            // Set the background frame color
            GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        }

        public void onDrawFrame(GL10 unused)
        {
            // Redraw background color
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        }

        public void onSurfaceChanged(GL10 unused, int width, int height)
        {
            GLES20.glViewport(0, 0, width, height);
        }
    }

}

 

GLSurfaceView的绘制过程要点

1,GLSurfaceview的渲染模式RenderMode

在onAttachedToWindow后就启动了一个无线循环的子线程,该子线程完成了整个绘制流程,并系统默认是负责不断刷新重绘,刷新的帧率是16FPS。从这里也可以看出来,GLSurfaceView系统默认是60ms就重绘一次,这样的耗性能的重绘操作一定是要用在那种有持续动画的效果才有意义。

当然,你也可以通过设置setRenderMode去设置主动刷新:

 
/**
 * Set the rendering mode. When renderMode is
 * RENDERMODE_CONTINUOUSLY, the renderer is called
 * repeatedly to re-render the scene. When renderMode
 * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface
 * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.
 *
* Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance * by allowing the GPU and CPU to idle when the view does not need to be updated. *

* This method can only be called after {@link #setRenderer(Renderer)} * * @param renderMode one of the RENDERMODE_X constants * @see #RENDERMODE_CONTINUOUSLY * @see #RENDERMODE_WHEN_DIRTY */ public void setRenderMode(int renderMode) { mGLThread.setRenderMode(renderMode); }

注解中提到:系统默认mode==RENDERMODE_CONTINUOUSLY,这样系统会自动重绘;mode==RENDERMODE_WHEN_DIRTY时,只有surfaceCreate的时候会绘制一次,然后就需要通过requestRender()方法主动请求重绘。同时也提到,如果你的界面不需要频繁的刷新最好是设置成RENDERMODE_WHEN_DIRTY,这样可以降低CPU和GPU的活动,可以省电。

 

 

2,事件处理

 

为了处理事件,一般都是继承GLSurfaceView类并重载它的事件方法。但是由于GLSurfaceView是多线程操作,所以需要一些特殊的处理。由于渲染器在独立的渲染线程里,你应该使用Java的跨线程机制跟渲染器通讯。queueEvent(Runnable)方法就是一种相对简单的操作。


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() { 
                    // 这个方法会在渲染线程里被调用 
                         public void run() { 
                             mMyRenderer.handleDpadCenter(); 
                         }}); 
                     return true; 
                 } 
   
                 return super.onKeyDown(keyCode, event); 
            } 
      } 
}
 

调用queueEvent就是给队列中添加runnable

public void queueEvent(Runnable r) {
 
    synchronized(sGLThreadManager) {
        mEventQueue.add(r);
        sGLThreadManager.notifyAll();
    }
 
}

在guardenRun()中有如下代码:

 


               if (! mEventQueue.isEmpty()) {
                    event = mEventQueue.remove(0);
                    break;
                }
                 
                ...
                 
                if (event != null) {
                    event.run();
                    event = null;
                    continue;
                }
 

这篇关于android GLSurfaceView渲染模式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/523562

相关文章

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

详解如何在React中执行条件渲染

《详解如何在React中执行条件渲染》在现代Web开发中,React作为一种流行的JavaScript库,为开发者提供了一种高效构建用户界面的方式,条件渲染是React中的一个关键概念,本文将深入探讨... 目录引言什么是条件渲染?基础示例使用逻辑与运算符(&&)使用条件语句列表中的条件渲染总结引言在现代

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)