我对一些非常简单的事情感到沮丧:使用Android的相机API拍摄照片(没有预览)。我一直在关注stackoverflow的几个答案,但没有成功。
最初我按照这个答案(@sush):How to take pictures from the camera without preview when my app starts?
但是从未调用 PictureCallback 。然后我按照这个答案(@Alex Cohn):
您正确地发现不应在startPreview()之前或之后立即调用takePicture()。 (onPictureTaken never called)
这让我尝试了三种解决方案。
第一个解决方案在SurfaceHolder中放置回调:
public class TestActivity extends Activity
{
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takeSnapShot();
}
@Override
protected void onPause()
{
clearCamera();
super.onPause();
}
private void takeSnapShot()
{
if (mCamera == null)
{
try { mCamera = Camera.open(); }
catch (Exception e) { e.printStackTrace(); }
SurfaceView surface = (SurfaceView) findViewById(R.id.preview);
surface.getHolder().addCallback(mSurfaceHolderCallback);
try { mCamera.setPreviewDisplay(surface.getHolder()); }
catch (IOException e) { e.printStackTrace(); }
mCamera.startPreview();
}
}
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback()
{
@Override
public void surfaceCreated(SurfaceHolder holder)
{
try
{
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
mCamera.takePicture(null, null, mPictureCallback);
}
catch (IOException e) { e.printStackTrace(); }
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
};
private final Camera.PictureCallback mPictureCallback = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
FileOutputStream outStream = null;
try
{
File dir_path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File pictureFile = new File(dir_path, "snapshot-test.jpg");
outStream = new FileOutputStream(pictureFile);
outStream.write(data);
outStream.close();
}
catch (FileNotFoundException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
finally { clearCamera(); }
}
};
private void clearCamera()
{
if (mCamera != null)
{
try
{
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
catch (final Exception e) { e.printStackTrace(); }
}
}
如果我只打一次 takeSnapShot ,这第一个解决方案就有效。不幸的是,我无法多次 mSurfaceHolderCallback 运行 SurfaceCreated 。
我的第二个解决方案是使用 PreviewCallback 。在这个解决方案中,我重新使用了 onPause :
public class TestActivity extends Activity
{
private Camera mCamera;
private boolean mReadyToTakePicture;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takeSnapShot();
}
private void takeSnapShot()
{
if (mCamera == null)
{
try { mCamera = Camera.open(); }
catch (Exception e) { e.printStackTrace(); }
mCamera.setPreviewCallback(mRawPreviewCallback);
SurfaceView surface = (SurfaceView) findViewById(R.id.preview);
try { mCamera.setPreviewDisplay(surface.getHolder()); }
catch (IOException e) { e.printStackTrace(); }
mCamera.startPreview();
}
}
private final Camera.PreviewCallback mRawPreviewCallback = new Camera.PreviewCallback()
{
@Override
public void onPreviewFrame(byte [] rawData, Camera camera)
{
int rawDataLength = 0;
if (rawData != null) { rawDataLength = rawData.length; }
if (rawDataLength > 0 && !mReadyToTakePicture)
{
mReadyToTakePicture = true;
mCamera.takePicture(null, null, mPictureCallback);
}
else { mReadyToTakePicture = false; }
}
};
private final Camera.PictureCallback mPictureCallback = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
FileOutputStream outStream = null;
mReadyToTakePicture = false;
try
{
File dir_path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File pictureFile = new File(dir_path, "snapshot-test.jpg");
outStream = new FileOutputStream(pictureFile);
outStream.write(data);
outStream.close();
}
catch (FileNotFoundException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
finally { clearCamera(); }
}
};
private void clearCamera()
{
if (mCamera != null)
{
try
{
mReadyToTakePicture = false;
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
catch (final Exception e) { e.printStackTrace(); }
}
}
}
在此解决方案中,永远不会调用 mRawPreviewCallback 和 mPictureCallback 。
我的最后一个例子是使用 AsyncTask 在实际拍照之前等待一段时间。希望这会给预览设置足够的时间。在这个解决方案中,我重新使用了 onPause 和 clearCamera :
public class TestActivity extends Activity
{
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takeSnapShot();
}
private void takeSnapShot()
{
if (mCamera == null)
{
try { mCamera = Camera.open(); }
catch (Exception e) { e.printStackTrace(); }
SurfaceView surface = (SurfaceView) findViewById(R.id.preview);
try { mCamera.setPreviewDisplay(surface.getHolder()); }
catch (IOException e) { e.printStackTrace(); }
mCamera.startPreview();
new CameraTask().execute(mCamera);
}
}
private class CameraTask extends AsyncTask<Camera, Void, Void>
{
protected String doInBackground(Camera... cameras)
{
try { Thread.sleep(1500); } catch (InterruptedException e)
{ e.printStackTrace(); }
mCamera = cameras[0];
mCamera.takePicture(null, null, mPictureCallback);
return mPicturePath;
}
private final Camera.PictureCallback mPictureCallback = new Camera.PictureCallback()
{
@Override
public void onPictureTaken(byte[] data, Camera camera)
{
FileOutputStream outStream = null;
try
{
File dir_path =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File pictureFile = new File(dir_path, "snapshot-test.jpg");
mPicturePath = pictureFile.getAbsolutePath();
outStream = new FileOutputStream(pictureFile);
outStream.write(data);
outStream.close();
}
catch (FileNotFoundException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
finally { clearCamera(); }
}
};
}
}
与解决方案2 一样,永远不会调用 onPictureTaken 。
在所有示例中, SurfaceView 的布局如下(无需预览):
<SurfaceView
android:id="@+id/preview"
android:layout_width="1dp"
android:layout_height="1dp"></SurfaceView>
此时我的想法已经不多了。我的第一个例子是成功拍摄了一张照片,所以如果我至少可以强迫应用程序多次运行 surfaceCreated ,它应该可以正常工作。有什么想法吗?
答案 0 :(得分:0)
好的,所以我之前在姜饼设备上遇到过这个问题。 执行以下操作:
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(final byte[] originalData, Camera camera) {
// logic here
});
而不是:
mCamera.takePicture(null, null,myCallback);
private PictureCallback mPicallback = new PictureCallback(){ };