Android Camera.takePicture失败了

作为一个学习练习,我正在编写一个安全应用程序,当发生任意事件时,需要打开相机,拍照并关闭相机,而不必担心闪光,对焦或显示预习。 我跟着在线演示并制作了一个可以拍照的工作应用程序,但它使用预览和所有这些。 所以我开始努力让它在没有预览的情况下工作。 无论如何,我不断得到’takePicture failed’exception,而且我没有任何世俗的想法。 我希望有更多使用Camera API经验的人可以看看并指出我的解决方案。 以下是我的相关文件。 我正在使用最新的Android Studio并在Galaxy S4上进行测试。

[MainActivity.java]

package com.g5digital.cam2; import android.content.pm.PackageManager; import android.hardware.Camera; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; import android.widget.Toast; import java.io.IOException; public class MainActivity extends ActionBarActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private Button button; private int cameraId; private Camera camera; private CameraPreview camPreview; private LinearLayout container; private Camera.Parameters camParms; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); container = (LinearLayout)findViewById(R.id.container); button = (Button)findViewById(R.id.button); button.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onClick(View view) { openCamera(); try { if (camera != null) { PhotoHandler ph = new PhotoHandler(this, camera); camera.takePicture(null, null, ph); // Commented until takePicture() works /*(new Handler()).postDelayed(new Runnable() { @Override public void run() { MainActivity.this.closeCamera(); } }, 1000);*/ } } catch (Exception e) { closeCamera(); Log.d(TAG, e.getMessage()); e.printStackTrace(); } } private void openCamera() { // do we have a camera? if (!getPackageManager() .hasSystemFeature(PackageManager.FEATURE_CAMERA)) { Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG) .show(); } else { closeCamera(); cameraId = findFrontFacingCameraId(); if (cameraId < 0) { Toast.makeText(this, "No front facing camera found.", Toast.LENGTH_LONG).show(); } else { camera = Camera.open(cameraId); try { setCamParms(); setCamPreview(); camera.startPreview(); } catch (Exception e) { closeCamera(); e.printStackTrace(); finish(); return; } } } } private void closeCamera() { if (camera != null) { camera.release(); camera = null; } } private int findFrontFacingCameraId() { int camera_id = -1; // Search for the front facing camera int numberOfCameras = Camera.getNumberOfCameras(); for (int i = 0; i < numberOfCameras; i++) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { Log.d(TAG, "Camera found"); camera_id = i; break; } } return camera_id; } private void setCamParms() { if (camParms == null && camera != null) { camParms = camera.getParameters(); camParms.setFlashMode("Off"); } if (camera != null) { camera.setParameters(camParms); camera.setDisplayOrientation(90); } } private void setCamPreview() throws IOException { if (camPreview == null && camera != null) { camPreview = new CameraPreview(this, camera); } if (camera != null) { camera.setPreviewDisplay(camPreview.getHolder()); } } } 

[CameraPreview.java]

 package com.g5digital.cam2; import android.content.Context; import android.hardware.Camera; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import java.io.IOException; public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private Context context; private Camera camera; private SurfaceHolder holder; private static final String TAG = "CameraPreview"; public CameraPreview(Context c, Camera cam) { super(c); context = c; camera = cam; holder = getHolder(); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { try { camera.setPreviewDisplay(holder); camera.startPreview(); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } catch (Exception e) { // Probably getting "called after release()" message e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (holder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { camera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { camera.setPreviewDisplay(holder); camera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { // } } 

[PhotoHandler.java]

 package com.g5digital.cam2; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.hardware.Camera; import android.os.Environment; import android.util.Log; import android.widget.Toast; import java.io.File; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; public class PhotoHandler implements Camera.PictureCallback { private final Context context; private final Camera camera; public PhotoHandler(Context context, Camera c) { this.context = context; this.camera = c; } @Override public void onPictureTaken(byte[] bytes, Camera cam) { Log.i("PhotoHandler", "Picture taken!"); File pictureFileDir = getDir(); if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) { Log.d("PhotoHandler", "Can't create directory to save image."); Toast.makeText(context, "Can't create directory to save image.", Toast.LENGTH_LONG).show(); return; } Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); int width = bmp.getWidth(); int height = bmp.getHeight(); Matrix matrix = new Matrix(); matrix.postRotate(270); Bitmap rotatedBitmap = Bitmap.createBitmap(bmp, 0, 0, width, height, matrix, true); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String date = dateFormat.format(new Date()); String photoFile = "Picture_" + date + ".jpg"; String filename = pictureFileDir.getPath() + File.separator + photoFile; File pictureFile = new File(filename); try { FileOutputStream fos = new FileOutputStream(pictureFile); boolean result = rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fos); //fos.write(bytes); fos.close(); if (result) { Toast.makeText(context, "New Image saved:" + photoFile, Toast.LENGTH_LONG).show(); } else { Toast.makeText(context, "Couldn't save image:" + photoFile, Toast.LENGTH_LONG).show(); } camera.startPreview(); } catch (Exception error) { Log.d("PhotoHandler", "File" + filename + "not saved: " + error.getMessage()); Toast.makeText(context, "Image could not be saved.", Toast.LENGTH_LONG).show(); } } private File getDir() { File sdDir = Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); return new File(sdDir, "CameraAPIDemo"); } } 

[AndroidManifest.xml中]

                  

[activity_main.xml中]

  

[LogCat输出]

 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 D/MainActivity﹕ takePicture failed 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ java.lang.RuntimeException: takePicture failed 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.native_takePicture(Native Method) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.takePicture(Camera.java:1194) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.hardware.Camera.takePicture(Camera.java:1139) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.g5digital.cam2.MainActivity.onClick(MainActivity.java:66) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.view.View.performClick(View.java:4475) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.view.View$PerformClick.run(View.java:18786) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Handler.handleCallback(Handler.java:730) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:92) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.os.Looper.loop(Looper.java:137) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5419) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at java.lang.reflect.Method.invokeNative(Native Method) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:525) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187) 01-29 14:55:45.826 5853-5853/com.g5digital.cam2 W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003) 01-29 14:55:45.836 5853-5853/com.g5digital.cam2 W/System.err﹕ at dalvik.system.NativeStart.main(Native Method) 

不,拍照必须显示预览。 熟练的人发明了不少解决方法,例如看看没有预览的拍照Android , Android:可以用没有UI的服务用相机拍照 , 如何使用相机在后台拍照服务Android的? …

但请记住,要求不是出于技术要求,而是出于隐私目的。 系统继续发展并防范新发现的变通方法。

也许在S4上隐藏预览最强大的方法是使用SurfaceTexture,但不可见地显示它,例如从视口移开。