Как правильно использовать setZOrderMediaOverlay на Android? - PullRequest
8 голосов
/ 25 апреля 2011

Как и многие другие, я пытаюсь рисовать трехмерные объекты (используя GLSurfaceView) при предварительном просмотре камеры (используя SurfaceView) вместе с некоторыми кнопками, расположенными сверху. На самом деле я получил работающий прототип, но не смог заставить работать onResume корректно. После возобновления GLSurfaceView остается позади и больше не отображается. Я знаю, что это работает, потому что я могу видеть чертеж нормально, если я удаляю SurfaceView из макета.

Цель - Nexus One, работающий сток 2.3.3 ROM.

Вот макет XML: </p> <pre><code><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 и реализует логику предварительного просмотра камеры.

Это прекрасно работает, когда начинается действие. После того, как я запускаю другое действие (например, нажатием одной из кнопок) и завершаю это действие, основное действие возобновляется, но трехмерные объекты больше не отображаются.

Я нашел это обсуждение , где упоминается, что setZOrderMediaOverlay() поможет решить эту проблему z-упорядочения. Кроме того, в документе Android для 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 -> VISIBLE
GLPreview: surfaceCreated
GLPreview: surfaceChanged, format=1, w=800, h=480

Итак, я предположил, что setZOrderMediaOverlay() нужно вызывать либо в onResume(), либо в конструкторе. Однако я пробовал различные комбинации setZOrderMediaOverlay() с true или false в классах GLSurfaceView или SurfaceView, но ни одна из них не помогла решить проблему.

Я относительно новичок в программировании на Android. Я зашел так далеко, но на данный момент мне нужна помощь. Если кто-то, кто успешно использовал setZOrderMediaOverlay() в этом сценарии и работал с onResume(), сообщите мне, как это нужно сделать.

Заранее большое спасибо!

Ответы [ 2 ]

14 голосов
/ 17 мая 2011

Я боролся с той же проблемой в течение некоторого времени, но считаю, что приведенный ниже код теперь работает.(Он продолжает работать после паузы / блокировки независимо от того, включена камера или нет).

Во-первых, у меня нет определенных видов и т. Д., Определенных в файле макета - они созданы в коде.Следующее вызывается из основного метода onCreate (). Обратите внимание на setZOrderMediaOverlay () на augScreen.

Я ничего особенного не сделал в onPause () или onResume (), кроме передачи 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));
0 голосов
/ 18 декабря 2011

Ответ от Awila_Tech мне тоже помог. Я использовал GLSurfaceView и аккуратно вызывал его onPause и onResume в onPause и onResume Activity, но 1 из 5 раз мой экран оставался черным, пока вызывался фактический 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();
    }
}
...