文章

Android GLSurfaceView 清屏问题

Android GLSurfaceView 清屏问题

编写了一个通过 GLSurfaceView 渲染视频画面的逻辑,但是发现移除之后会残留最后一帧,排查了一天终于找到了问题。

先说结论,只要管理好他的生命周期,系统会处理好清屏,不会发生残留。

由于问题太傻逼,先卖个关子,问题的原因在最后面。下面是网上找的不太行的方法:

1
2
3
4
5
public void onDrawFrame(GL10 gl) {
     // 清屏逻辑:仅绘制背景,无法做到透明
     GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);    
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}

的确能清屏,但是做不到透明,我的目标是移除之后原本父视图是什么颜色就还是什么颜色,这个逻辑实际上是将 GLSurfaceView 显示区域清理成黑色了。

又尝试通过启用混合模式清理成透明的,测试后没有任何效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 // 配置OpenGL版本(这里使用ES 2.0)
    setEGLContextClientVersion(2);
    setEGLContextFactory(createContextFactory());

 // 关键:配置EGL支持8位Alpha通道
 setEGLConfigChooser(8, 8, 8, 8, 16, 0); // R(8), G(8), B(8), A(8), 深度缓冲16位
 // 设置Surface为透明格式
 getHolder().setFormat(PixelFormat.TRANSLUCENT);
 // 视图自身背景设为透明
 setBackgroundColor(Color.TRANSPARENT);

public void onDrawFrame(GL10 gl) {
     // 启用混合模式,允许透明叠加
     // GLES20.glEnable(GLES20.GL_BLEND);
     // GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
     // 清屏逻辑:仅绘制背景,无法做到透明
     GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);    
     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
}

还可以通过 Canvas 清屏,也不行

1
2
3
Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, clearPaint); 

揭晓答案

最后发现虽然我置空了对象,但是他还躺在父视图上,因为移除的逻辑写错了,是我没有掌握好安卓的 removeView 方法,默认情况下直接调用实际上是省略了 this ,意思是从当前视图上移除传入参数的子视图,可恰巧我这个 GLSurfaceView 对象不是当前视图的子视图,所以误认为移除了,但实际还在那里。

1
2
3
4
5
  ViewGroup parent = (ViewGroup) uiView.getParent();
  if (parent != null) {
-  removeView(uiView);
+  parent.removeView(uiView);
  }

这个方法感觉很难用,iOS 里有个 removeFromSuperView 的方法很好用。

本文由作者按照 CC BY 4.0 进行授权