在SurfaceView加载Camera Preview时显示我的布局

时间:2011-08-19 08:53:43

标签: android loading surfaceview android-camera

我有一个带开始按钮的简单屏幕。按下“开始”按钮后,我想转到带有SurfaceView的新屏幕以显示摄像机。

一切正常,但相机需要一段时间才能加载,这给了我一个黑屏。 我想加载新的布局。并且在装载后启动相机......

因此,我在后台线程中完成所有相机加载,但仍然,我得到一个黑屏...... 这是我的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/RelativeLayout1"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/blue_bg">

    <SurfaceView
        android:id="@+id/surface_camera"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginLeft="25dp"
        android:layout_marginRight="25dp"
        android:layout_below="@id/scan_header"
        android:layout_above="@id/scan_footer">
    </SurfaceView>

</RelativeLayout>

以下是我的Activity中的方法,它加载了新视图:

private void setContent()
{
    setContentView(R.layout.scan)

    Thread t = new Thread()
    {
        public void run()
        {

            final SurfaceView mSurfaceView = (SurfaceView)findViewById(R.id.surface_camera);
            final SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder();

            try
            {   
                cameraView = new CameraView();
                mSurfaceHolder.addCallback(cameraView);
                cameraView.setPictureListener(SunpluggedActivity.this);
                mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

            } catch(Exception e)
            {
                Log.d(TAG, "Another exception");
                e.printStackTrace();
            }
        }
    };
    t.start();
}

为什么新的布局没有显示,直到线程完成加载相机?

编辑:我已经尝试在Thread内部的Thread.sleep(200)睡了一段时间......当我这样做时,新的布局会被显示出来,但相机永远不会启动......

1 个答案:

答案 0 :(得分:22)

好吧,问题是我在xml布局中使用了SurfaceView。 你打电话的那一刻:setContentView(your_layout) - &gt; XML文件被夸大了。 这意味着,SurfaceView也会膨胀。这再次意味着调用SurfaceView onSurfaceCreated方法,触发打开相机等。

因此,整个过程需要一段时间,因此,您之前的活动(例如,使用SurfaceView启动活动的活动)似乎没有响应......

我在BG线程中创建CameraView的解决方案解决了无响应问题。但未能在SurfaceView中显示Camera输出。

解决方案是从xml中删除SurfaceView。这将立即启动您的活动(因为SurfaceView&amp; Camera未实例化)。 加载新的“活动”布局后,可以以编程方式将新的SurfaceView添加到屏幕上。当然,这也需要时间,但您的UI会快速切换到新活动,并且您可以在SurfaceView和Camera加载时显示加载程序!

SO:从XML中删除SURFACEVIEW - &gt;在程序上添加它: 启动活动:

public class Launch extends Activity implements OnClickListener 
{
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main);
        Button btn = (Button)findViewById(R.id.button1);
        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent(Launch.this, SurfaceTestActivity.class);
        startActivity(intent);  
    }
}

Main.xml(只是一个启动新活动的按钮)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/RelativeLayout1"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ff6600">

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
</RelativeLayout>

这是第二个活动(包含SurfaceView)

public class SurfaceTestActivity extends Activity {

    private Context mContext;
    private CameraView cameraView;
    private Handler mHandler = new Handler();
    private final Runnable mLoadCamera = new Runnable()
    {
        public void run()
        {
            startCamera();
        }
    };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContent();
        mContext = getApplicationContext();
    }

    private void startCamera()
    {
        RelativeLayout rl = (RelativeLayout)findViewById(R.id.surface_camera);
        SurfaceView surfaceView = new SurfaceView(mContext);
        final SurfaceHolder mSurfaceHolder = surfaceView.getHolder();

        try
        {  
            cameraView = new CameraView();
            mSurfaceHolder.addCallback(cameraView);
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        } catch(Exception e)
        {
            Log.d("debug", "Another exception");
            e.printStackTrace();
        }

        if(rl != null && surfaceView != null)
            rl.addView(surfaceView);
    }

    private void setContent()
    {
        setContentView(R.layout.scan);

        // Post the Runnable with a Slight delay -> than your layout will be 
        // shown. Without the delay -> your UI will feel inresponsive
        mHandler.postDelayed(mLoadCamera, 100);
    }
}

这是第二个Activity的布局(没有SURFACEVIEW)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:id="@+id/RelativeLayout1"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#ff6600">
    <RelativeLayout 
        android:id="@+id/header"
        android:layout_width="fill_parent" android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:text="Explanation Txt"></TextView>
    </RelativeLayout>
    <RelativeLayout 
        android:id="@+id/footer"
        android:layout_width="fill_parent" android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <TextView
            android:layout_width="wrap_content" android:layout_height="wrap_content"
            android:text="Explanation Txt"></TextView>
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/surface_camera"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/footer"
        android:layout_below="@+id/header" 
        android:background="#ff0066">

    </RelativeLayout>

</RelativeLayout>

最后,要完成答案,这里是CameraView()的代码。打开相机并显示内容真的只是一个简单的实现:

public class CameraView  implements SurfaceHolder.Callback{

    // Variables
    private Camera mCamera = null;
    private boolean mPreviewRunning = false;
    private boolean mProcessing = false;
    private int mWidth = 0;
    private int mHeight = 0;

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) 
    {   
        if(mPreviewRunning )
        {
            mCamera.stopPreview();
        }

        // Store width and height
        mWidth = width;
        mHeight = height;

        // Set camera parameters
        Camera.Parameters p = mCamera.getParameters();
        mCamera.setParameters(p);

        if(android.os.Build.VERSION.SDK_INT >= 8)
        {   // If API >= 8 -> rotate display...
            mCamera.setDisplayOrientation(90);
        }

        try
        {
            mCamera.setPreviewDisplay(holder);
        } catch(IOException e)
        {
            e.printStackTrace();
        }

        mCamera.startPreview();
        mPreviewRunning = true;

    }

    @Override
    public void surfaceCreated(final SurfaceHolder holder) 
    {
        try {
            mCamera = Camera.open();
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) 
        {
            mCamera.release();
            mCamera = null;
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        if(mCamera != null)
        {
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.setPreviewCallback(null);
            mPreviewRunning = false;
            mCamera.release();
            mCamera = null;
        }   
    }
}