【问题标题】:How to properly use setZOrderMediaOverlay on Android?如何在 Android 上正确使用 setZOrderMediaOverlay?
【发布时间】:2011-08-12 07:51:48
【问题描述】:

像许多其他人一样,我正在尝试在相机预览(使用 SurfaceView)上绘制 3D 对象(使用 GLSurfaceView),以及放置在顶部的一些按钮。我实际上得到了一个原型工作,但我无法让 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>

所有这些都包含在 &lt;merge&gt; 块中,但由于某种原因,我无法将其包含在上面的 &lt;code&gt; 列表中。 PreviewSurfaceView 的扩展类,实现了相机预览逻辑。

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

我找到了this discussion,其中提到setZOrderMediaOverlay() 将有助于解决这个z-ordering 问题。此外,Android document for setZOrderMediaOverlay() 表示应该在“将表面视图的包含窗口附加到窗口管理器之前”调用此函数。我不知道我应该如何解释该语句,所以我将调试语句放在代码中以查看事件顺序。 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); } }

这是我启动应用程序时的事件顺序:

GLPreview:OnResume GLPreview:onAttachedToWindow GLPreview:onWindowVisibilityChanged -> 可见 GLPreview:表面创建 GLPreview:surfaceChanged,格式=1,w=800,h=480

所以我假设setZOrderMediaOverlay() 需要在onResume() 或构造函数中调用。但是,我在GLSurfaceViewSurfaceView 类中尝试了setZOrderMediaOverlay()truefalse 的各种组合,但都没有解决问题。

在 Android 编程方面,我相对较新。我已经走了这么远,但在这一点上我需要一些帮助。如果有人在这种情况下成功使用 setZOrderMediaOverlay() 并让它与 onResume() 一起工作,请告诉我需要如何完成。

提前非常感谢!

【问题讨论】:

标签: android surfaceview z-order glsurfaceview


【解决方案1】:

我已经为同样的问题苦苦挣扎了一段时间,但相信下面的代码现在可以工作了。 (无论相机是开还是关,它在暂停/锁定后继续工作)。

首先,我没有在布局文件中定义任何视图等 - 它们是在代码中创建的。以下是从主 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));

【讨论】:

  • 谢谢,在onCreate() 中调用setZOrderMediaOverlay() 解决了这个问题。顺便说一句,我还有 XML 布局文件;我没有转换应用程序以在代码中构建视图。我知道我没有在问题中提到这一点,但同一个应用程序有一些用于在相机预览表面上绘制的代码(显示 fps 的简单 DrawText)。现在我必须弄清楚为什么在我实施 setZOrderMediaOverlay() 更改后这段代码停止工作。
  • “不工作”是指代码被调用,我看到了相机预览和 3D 对象,但 fps 文本不再绘制在相机预览表面上。嗯嗯嗯。
【解决方案2】:

Awila_Tech 的回答也帮助了我。我使用了 GLSurfaceView 并在活动的 onPause 和 onResume 中巧妙地调用了它的 onPause 和 onResume,但是在调用实际的 onDrawFrame 时,我的屏幕有五分之一的时间保持黑色。

总结一下:

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();
    }
}

【讨论】:

  • Pete,你不应该在 mGLSurfaceView 之前调用 super.onPause() 和 super.onResume() 吗?
猜你喜欢
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 2016-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多