创建好了EGL环境后,我们就可以自定义我们的GLSurfaceView,可以用来替代系统的GLSurfaceView。
可以分成以下几点
- 继承SurfaceView,并实现其CallBack回调
- 自定义GLThread线程类,主要用于OpenGL的绘制操作
- 添加设置Surface和EglContext的方法
- 提供和系统GLSurfaceView相同的调用方法
先看如何实现自己的SurfaceView
public abstract class BaseSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private Surface surface;
private EGLContext eglContext;
private EGLThread eglThread;
private EGLRender eglRender;
/**
* 视图更新模式
* RENDERMODE_WHEN_DIRTY 懒更新
* RENDERMODE_CONTINUOUSLY 主动更新
**/
public final static int RENDERMODE_WHEN_DIRTY = 0;
public final static int RENDERMODE_CONTINUOUSLY = 1;
private int mRenderMode = RENDERMODE_CONTINUOUSLY;
public BaseSurfaceView(Context context) {
this(context, null);
}
public BaseSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getHolder().addCallback(this);
}
public void setRender(EGLRender eglRender) {
this.eglRender = eglRender;
}
public void setRenderMode(int mRenderMode) {
if (eglRender == null) {
throw new RuntimeException("must set render before");
}
this.mRenderMode = mRenderMode;
}
public void setSurfaceAndEglContext(Surface surface, EGLContext eglContext) {
this.surface = surface;
this.eglContext = eglContext;
}
public EGLContext getEglContext() {
if (eglThread != null) {
return eglThread.getEglContext();
}
return null;
}
public void requestRender() {
if (eglThread != null) {
eglThread.requestRender();
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (surface == null) {
surface = holder.getSurface();
}
eglThread = new EGLThread(new WeakReference<BaseSurfaceView>(this));
eglThread.isCreate = true;
eglThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
eglThread.width = width;
eglThread.height = height;
eglThread.isChange = true;
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
eglThread.onDestroy();
eglThread = null;
surface = null;
eglContext = null;
}
public interface EGLRender {
/**
* 视图创建时
**/
void onSurfaceCreated();
/**
* 视图发生变化时
*
* @param width 当前视图宽度
* @param height 当前视图高度
**/
void onSurfaceChanged(int width, int height);
/**
* 数据更新时
**/
void onDrawFrame();
}
/**
* 维护egl生命周期的线程
**/
public static class EGLThread extends Thread {
private WeakReference<BaseSurfaceView> eglSurfaceViewWeakReference;
private EglHelper eglHelper = null;
private Object object = null;
private boolean isExit = false;
private boolean isCreate = false;
private boolean isChange = false;
private boolean isStart = false;
private int width;
private int height;
public EGLThread(WeakReference<BaseSurfaceView> eglSurfaceViewWeakReference) {
this.eglSurfaceViewWeakReference = eglSurfaceViewWeakReference;
}
@Override
public void run() {
super.run();
isExit = false;
isStart = false;
object = new Object();
eglHelper = new EglHelper();
eglHelper.initEgl(eglSurfaceViewWeakReference.get().surface, eglSurfaceViewWeakReference.get().eglContext);
while (true) {
if (isExit) {
//释放资源
release();
break;
}
if (isStart) {
if (eglSurfaceViewWeakReference.get().mRenderMode == RENDERMODE_WHEN_DIRTY) {
synchronized (object) {
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else if (eglSurfaceViewWeakReference.get().mRenderMode == RENDERMODE_CONTINUOUSLY) {
try {
Thread.sleep(1000 / 60);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
throw new RuntimeException("mRenderMode is wrong value");
}
}
onCreate();
onChange(width, height);
onDraw();
isStart = true;
}
}
private void onCreate() {
if (isCreate && eglSurfaceViewWeakReference.get().eglRender != null) {
isCreate = false;
eglSurfaceViewWeakReference.get().eglRender.onSurfaceCreated();
}
}
private void onChange(int width, int height) {
if (isChange && eglSurfaceViewWeakReference.get().eglRender != null) {
isChange = false;
eglSurfaceViewWeakReference.get().eglRender.onSurfaceChanged(width, height);
}
}
private void onDraw() {
if (eglSurfaceViewWeakReference.get().eglRender != null && eglHelper != null) {
eglSurfaceViewWeakReference.get().eglRender.onDrawFrame();
if (!isStart) {
eglSurfaceViewWeakReference.get().eglRender.onDrawFrame();
}
eglHelper.swapBuffers();
}
}
/**
* 通知更新视图
**/
private void requestRender() {
if (object != null) {
synchronized (object) {
object.notifyAll();
}
}
}
public void onDestroy() {
isExit = true;
//通知更新视图
requestRender();
}
/**
* 释放egl环境
**/
public void release() {
if (eglHelper != null) {
eglHelper.destoryEgl();
eglHelper = null;
object = null;
eglSurfaceViewWeakReference = null;
}
}
public EGLContext getEglContext() {
if (eglHelper != null) {
return eglHelper.getmEglContext();
}
return null;
}
}
}
我们把上一节的创建egl环境的内容用上了,直接定义了一个线程用于管理egl的生命周期,并且定义了EGLRender类,暴露三个方法,这一点直接是模仿了SurfaceHolder.Callback的三个回调。
然后我们看下如果继承了BaseSurfaceView的EGLRender应该怎么写,如下:
public class MyRender implements BaseSurfaceView.EGLRender {
public MyRender() {
}
@Override
public void onSurfaceCreated() {
}
@Override
public void onSurfaceChanged(int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame() {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
}
}
和上一节的内容很类似,只是把这部分的写法放在了对应的生命周期方法中。
然后我们继承BaseSurfaceView看下如何写,如下:
public class EGlSurfaceView extends BaseSurfaceView {
public EGlSurfaceView(Context context) {
this(context, null);
}
public EGlSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public EGlSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setRender(new MyRender());
setRenderMode(BaseSurfaceView.RENDERMODE_WHEN_DIRTY);
}
}
我们设置了上面定义的MyRender为EGlSurfaceView的生命周期操作类,并且设置了渲染模式,最后看下如何调用,如下:
public class EglSurfaceActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_egl);
}
}
然后是布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
<EGlSurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
使用起来很简单,现在也没有增加多余的操作,只是用于做最简单的显示,最终效果图:
嗯,显示出了绿色,颜色合适。