如何在Android上正确使用setZOrderMediaOverlay?

像许多其他人一样,我正在试图在相机预览(使用SurfaceView)上绘制3D对象(使用GLSurfaceView)以及放置在顶部的一些button。 我实际上有一个原型工作,但我不能让onResume正常工作。 简历后,GLSurfaceView留在后面,不再可见。 我知道它正在工作,因为如果我从布局中删除SurfaceView,我可以看到图纸很好。

目标是Nexus One,运行库存2.3.3 ROM。

这是布局xml:

 <com.example.cameratest.GLPreview android:id="@+id/cubes" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <com.example.cameratest.Preview android:id="@+id/camera" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/buttongroup" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_gravity="right" android:gravity="center"> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonClose"></Button> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonMode"></Button> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:id="@+id/buttonCameraInfo"></Button> </LinearLayout> 

所有这些被封装在一个<merge>块中,但由于某种原因,我不能将它包含在上面的<code>列表中。 Preview是扩展SurfaceView并实现相机预览逻辑的类。

这项活动启动时正常工作。 在我启动另一个活动(例如,通过按下其中一个button)并完成该活动后,主要活动恢复,但3D对象不再可见。

我发现这个讨论提到setZOrderMediaOverlay()将有助于解决这个z顺序问题。 另外, 用于setZOrderMediaOverlay()的Android文档说这个函数应该在“表面视图的包含窗口被附加到窗口pipe理器之前”被调用。 我不知道应该如何解释这个语句,所以我把代码中的debugging语句看成事件的顺序。 以下是GLSurfaceView代码的外观:

 public class GLPreview extends GLSurfaceView { private static final String TAG = "GLPreview"; public GLPreview(Context context, AttributeSet attrs) { super(context, attrs); // this.setZOrderMediaOverlay(true); } public void onPause() { super.onPause(); Log.d(TAG, "GLPreview: OnPause"); } public void onResume() { // this.setZOrderMediaOverlay(true); super.onResume(); Log.d(TAG, "GLPreview: OnResume"); } public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "GLPreview: surfaceCreated"); super.surfaceCreated(holder); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.d(TAG, String.format("GLPreview: surfaceChanged, format=%d, w=%d, h=%d", format, w, h)); super.surfaceChanged(holder, format, w, h); } public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "GLPreview: surfaceDestroyed"); super.surfaceDestroyed(holder); } protected void onAttachedToWindow() { Log.d(TAG, "GLPreview: onAttachedToWindow"); super.onAttachedToWindow(); } protected void onDetachedFromWindow() { Log.d(TAG, "GLPreview: onDetachedFromWindow"); super.onDetachedFromWindow(); } protected void onWindowVisibilityChanged (int vis) { String newVisibility; switch (vis) { case View.GONE: newVisibility = "GONE"; break; case View.INVISIBLE: newVisibility = "INVISIBLE"; break; case View.VISIBLE: newVisibility = "VISIBLE"; break; default: newVisibility = String.format("Unknown constant %d", vis); } Log.d(TAG, String.format("GLPreview: onWindowVisibilityChanged -> %s", newVisibility)); super.onWindowVisibilityChanged(vis); } }
public class GLPreview extends GLSurfaceView { private static final String TAG = "GLPreview"; public GLPreview(Context context, AttributeSet attrs) { super(context, attrs); // this.setZOrderMediaOverlay(true); } public void onPause() { super.onPause(); Log.d(TAG, "GLPreview: OnPause"); } public void onResume() { // this.setZOrderMediaOverlay(true); super.onResume(); Log.d(TAG, "GLPreview: OnResume"); } public void surfaceCreated(SurfaceHolder holder) { Log.d(TAG, "GLPreview: surfaceCreated"); super.surfaceCreated(holder); } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { Log.d(TAG, String.format("GLPreview: surfaceChanged, format=%d, w=%d, h=%d", format, w, h)); super.surfaceChanged(holder, format, w, h); } public void surfaceDestroyed(SurfaceHolder holder) { Log.d(TAG, "GLPreview: surfaceDestroyed"); super.surfaceDestroyed(holder); } protected void onAttachedToWindow() { Log.d(TAG, "GLPreview: onAttachedToWindow"); super.onAttachedToWindow(); } protected void onDetachedFromWindow() { Log.d(TAG, "GLPreview: onDetachedFromWindow"); super.onDetachedFromWindow(); } protected void onWindowVisibilityChanged (int vis) { String newVisibility; switch (vis) { case View.GONE: newVisibility = "GONE"; break; case View.INVISIBLE: newVisibility = "INVISIBLE"; break; case View.VISIBLE: newVisibility = "VISIBLE"; break; default: newVisibility = String.format("Unknown constant %d", vis); } Log.d(TAG, String.format("GLPreview: onWindowVisibilityChanged -> %s", newVisibility)); super.onWindowVisibilityChanged(vis); } } 

下面是启动应用程序时的事件序列:

 GLPreview:OnResume
 GLPreview:onAttachedToWindow
 GLPreview:onWindowVisibilityChanged  - > VISIBLE
 GLPreview:surfaceCreated
 GLPreview:surfaceChanged,format = 1,w = 800,h = 480

所以我认为setZOrderMediaOverlay()需要在onResume()或构造函数中调用。 然而,我尝试了setZOrderMediaOverlay()truefalse ,在GLSurfaceViewSurfaceView类中的各种组合,但没有一个帮助解决了这个问题。

在Android编程方面,我相对较新。 我到目前为止,但在这一点上,我需要一些帮助。 如果有人在这个场景中成功使用了setZOrderMediaOverlay() ,并使用onResume()让我知道这是如何完成的。

提前感谢!

Solutions Collecting From Web of "如何在Android上正确使用setZOrderMediaOverlay?"

一段时间以来,我一直在努力解决同样的问题,但相信下面的代码现在可以工作。 (无论相机是开还是关,暂停/locking后都会继续工作)。

首先,我没有在布局文件中定义任何视图等 – 它们是在代码中创build的。 以下是从主onCreate()方法调用 – 请注意augScreen上的setZOrderMediaOverlay()。

除了将onPause()和onResume()传递给augScreen之外,我在onPause()或onResume()中没有做任何特殊的处理。

  // 1 - Camera Preview camScreen = new CameraPreview(this); setContentView(camScreen, new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); // 2 - 3D object display augScreen = new AR_SurfaceView(this, getViewRange()); addContentView(augScreen, new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); augScreen.setZOrderMediaOverlay(true); // 3 - Permanent overlay RelativeLayout overlayScreen = new OverlayView(this); addContentView(overlayScreen, new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); overlayScreen.setVisibility(View.VISIBLE); // 4 - UI buttons (toggleable) uiScreen = new UserInterfaceView(this); addContentView(uiScreen, new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); 

Awila_Tech的回答也帮助了我。 我使用了一个GLSurfaceView,并且在Activity的onPause和onResume中整齐的调用onPause和onResume,但是当我调用实际的onDrawFrame的时候,我的屏幕中只有1次保持黑屏。

总结:

 public class OpenGLApp extends Activity implements GLSurfaceView.Renderer { private GLSurfaceView mGLSurfaceView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mGLSurfaceView = new GLSurfaceView(this); mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 8); mGLSurfaceView.setRenderer(this); mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT); mGLSurfaceView.setKeepScreenOn(true); mGLSurfaceView.setDrawingCacheEnabled(true); mGLSurfaceView.setZOrderOnTop(true); setContentView(mGLSurfaceView); //... } @Override protected void onPause() { //... mGLSurfaceView.onPause(); super.onPause(); } @Override protected void onResume() { mGLSurfaceView.onResume(); //... super.onResume(); } }