看完了view,SurfaceView,GLSurfaceView的区别,想着每个用一下看看,结果在布局内写完加载就报错。
布局内配置
<android.opengl.GLSurfaceView
android:id="@+id/gls_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
崩溃日志
java.lang.NullPointerException
at android.opengl.GLSurfaceView.surfaceCreated(GLSurfaceView.java:531)
at android.view.SurfaceView.updateWindow(SurfaceView.java:601)
at android.view.SurfaceView.access$000(SurfaceView.java:94)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:183)
(备注:GLSurfaceView属于framework层,有些厂商是定制的,与标准的sdk代码会有些不同。)
找到GLSurfaceView的崩溃的那一行(实际位置GLSurfaceView.java:522)
public void surfaceCreated(SurfaceHolder holder) {
mGLThread.surfaceCreated();
}
既然是空指针异常,显然mGLThread对象为空。
由此,找到mGLThread初始化的地方
public void setRenderer(Renderer renderer) {
checkRenderThreadState();
if (mEGLConfigChooser == null) {
mEGLConfigChooser = new SimpleEGLConfigChooser(true);
}
if (mEGLContextFactory == null) {
mEGLContextFactory = new DefaultContextFactory();
}
if (mEGLWindowSurfaceFactory == null) {
mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
}
mRenderer = renderer;
mGLThread = new GLThread(mThisWeakRef);
mGLThread.start();
}
发现mGLThread是在渲染器设置的时候进行初始化
顺便再来看看GLSurfaceView的构造函数
/**
* Standard View constructor. In order to render something, you
* must call {@link #setRenderer} to register a renderer.
*(这里已经提示我们,必须先设置一个渲染器)
*/
public GLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
原来是画面加载的时候去调用渲染,但是布局里面没有设置渲染器所以就崩了。
网上常见的GLSurfaceView使用方法
...
GLSurfaceView mGLView = new GLSurfaceView(this);
mGLView.setRenderer(new DemoRenderer());
//设置渲染器,其中DemoRenderer实现GLSurfaceView.Renderer
setContentView(mGLView);
...
如果实在想在布局里使用的话,用DemoGLSurfaceView继承GLSurfaceView
构造函数里面设置好适配器。
DemoGLSurfaceView.java
package test.com.asproject;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/**
* Created by Seselin on 2016/4/1.
*/
public class DemoGLSurfaceView extends GLSurfaceView {
DemoRenderer mRenderer;
public DemoGLSurfaceView(Context context) {
super(context);
//为了可以激活log和错误检查,帮助调试3D应用,需要调用setDebugFlags()。
this.setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
mRenderer = new DemoRenderer();
this.setRenderer(mRenderer);
}
public DemoGLSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
//为了可以激活log和错误检查,帮助调试3D应用,需要调用setDebugFlags()。
this.setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
mRenderer = new DemoRenderer();
this.setRenderer(mRenderer);
}
public boolean onTouchEvent(final MotionEvent event) {
//由于DemoRenderer对象运行在另一个线程中,这里采用跨线程的机制进行处理。使用queueEvent方法
//当然也可以使用其他像Synchronized来进行UI线程和渲染线程进行通信。
this.queueEvent(new Runnable() {
@Override
public void run() {
}
});
return true;
}
class DemoRenderer implements GLSurfaceView.Renderer {
@Override
public void onDrawFrame(GL10 gl) {
//每帧都需要调用该方法进行绘制。绘制时通常先调用glClear来清空framebuffer。
//然后调用OpenGL ES其他接口进行绘制
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
}
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
//当surface的尺寸发生改变时,该方法被调用,。往往在这里设置ViewPort。或者Camara等。
gl.glViewport(0, 0, w, h);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 该方法在渲染开始前调用,OpenGL ES的绘制上下文被重建时也会调用。
//当Activity暂停时,绘制上下文会丢失,当Activity恢复时,绘制上下文会重建。
}
}
}
布局内配置
<test.com.asproject.DemoGLSurfaceView
android:id="@+id/gls_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
test.com.asproject.DemoGLSurfaceView>
到此,GLSurfaceView已经可以使用了。