【问题标题】:Show my Layout while SurfaceView is loading Camera Preview在 SurfaceView 加载相机预览时显示我的布局
【发布时间】:2011-08-19 08:53:43
【问题描述】:

我有一个带有开始按钮的简单屏幕。当按下开始按钮时,我想进入一个带有 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) 睡眠一段时间...当我这样做时,新的布局会立即显示,但相机永远不会启动...

【问题讨论】:

    标签: android loading surfaceview android-camera


    【解决方案1】:

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

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

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

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

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

    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>
    

    这是第二个 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;
            }   
        }
    }
    

    【讨论】:

    • Android 开发者指南还建议在 WorkerThread 中调用 Camera.open() 以避免阻塞 UI 线程。
    • 这段代码工作得很好......如果我想在上面添加我的布局怎么办?
    • 在 xml 中,创建一个相对布局,其中包含一个表面视图。这个 surfaceView 将是您的“相机”视图。在它之上,您可以添加所有布局。
    猜你喜欢
    • 2017-02-15
    • 2020-05-04
    • 2015-09-20
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    • 1970-01-01
    相关资源
    最近更新 更多