我有一个启动按钮一个简单的屏幕。当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;
}
}
}