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

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

因此,我将所有Camera都加载到后台线程中,但是仍然出现黑屏...
这是我的布局:

<?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中的方法,该方法将加载新 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();
}

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

编辑:我已经尝试在线程内的Thread.sleep(200) sleep 了一段时间。

最佳答案

好吧,问题是我在xml布局中使用了SurfaceView。
调用的时刻:setContentView(your_layout)-> XML文件膨胀。
这意味着SurfaceView也会膨胀。再次,这意味着调用了SurfaceView onSurfaceCreated方法,这将触发打开Camera等。

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

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

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

因此:从XML删除SURFACEVIEW->按程序添加:
启动 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(仅是启动新 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>

这是第二个 Activity (其中包含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;
        }
    }
}

10-06 07:27
查看更多