显示我的布局,而SurfaceView加载摄像头preVIEW我的、布局、摄像头、加载

2023-09-13 23:49:48 作者:无关磅礴,你就是宇宙。

我有一个启动按钮一个简单的屏幕。当pressed开始按钮,我想去一个新的屏,SurfaceView显示在相机中。

I have a simple screen with a start button. When the Start button is pressed, I want to go to a new Screen with a SurfaceView to show the Camera in.

一切工作正常,但相机需要一段时间来加载,这给了我一个黑色的屏幕。 我想新的布局来加载。而不是启动相机已经加载之后...

Everything works fine, but the Camera takes a while to load, and this gives me a black screen. I would like the new layout to load. And than start the camera after it has been loaded...

为此,我做的所有摄像头装在后台线程,不过,我得到一个黑色的屏幕... 这是我的布局:

Therefor, I do all Camera loading in a background thread, but still, I get a black screen... Here's my layout:

<?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>

下面是从我的活动,它加载新的视图中的方法:

Here is the method from my Activity, which loads the new view:

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

怎么来的,新的布局没有显示出来,直到线程完成装入相机?

How come, the new layout is not shown, until the thread has finished loading the camera?

编辑:我已经试过了Thread.sleep(200)的线程中休眠一段时间... ...当我做到这一点,新的布局immedeately显示,但相机从未开始......

I've tried Thread.sleep(200) within the Thread to sleep for some time... When I do that, the new Layout is shown immedeately, but the Camera never starts...

推荐答案

还好吧,问题是,我使用中的XML布局我SurfaceView。 你叫的那一刻:的setContentView(your_layout) - > XML文件膨胀。 这意味着,该SurfaceView膨胀为好。也就是说,再次,意味着SurfaceView onSurfaceCreated方法被调用,从而触发打开摄像机等。

Allright, the problem is that I used my SurfaceView within the xml layout. The moment you call: setContentView(your_layout) -> the XML file is inflated. That means, the SurfaceView is inflated as well. That, again, means that the SurfaceView onSurfaceCreated Methods is called, which triggers opening the Camera etc.

所以,这整个过程需要一段时间,因此,你的previous活动(如一个启动的SurfaceView活动)似乎是反应迟钝......

So, this whole process takes a while, hence, your previous Activity (e.g. the one launching the Activity with the SurfaceView) seems to be unresponsive...

我的解决方案,创造了CameraView在BG线程解决inresponsiveness。但未能显示在SurfaceView相机输出

My solution, of creating the CameraView in a BG thread solves the inresponsiveness. But failed to show the Camera output in the SurfaceView.

解决方案是从XML删除您SurfaceView。这将immedeately开始你的活动(因为SurfaceView和相机都没有实例化)。 一旦您的新活动的布局被装载,就可以通过编程添加一个新的SurfaceView到你的屏幕。当然,这需要时间,但是你的UI切换到新的活动迅速,并可以显示一个加载器,而SurfaceView和照相机加载!

The solution is to remove your SurfaceView from your xml. This will start your activity immedeately (since the SurfaceView & Camera are not instantiated). Once your new Activities layout is loaded, you can programmatically add a new SurfaceView to your screen. Off course, this takes time as well, but your UI switches to the new activity quickly, and you can show a loader while the SurfaceView and Camera are loading!

SO:删除XML中的SURFACEVIEW - >添加编程方式: 启动活动:

SO: REMOVE THE SURFACEVIEW FROM THE XML -> ADD IT PROGRAMATICALLY: Launch Activity:

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中(只是一个按钮,启动新的活动)

Main.xml (just a button to launch the new activity)

<?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)

Here's the Second Activity (Which contains the 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);
    }
}

和这里的第二个活动的布局(没有SURFACEVIEW)

And here's the second Activity's layout (WITHOUT A 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>

最后,为了完成答案,这里的code为CameraView()。这真的只是一个简单的实现来获得打开摄像头和显示的内容:

Finally, to complete the answer, here's the code for the CameraView(). It really is just a simple implementation to get open the Camera and Display the contents:

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