Android:java.lang.RuntimeException:takePicture失败

我正在尝试捕捉surfaceview的图像。 但是,每次触摸屏幕时,应用程序都会崩溃并出现以下exception:

01-05 21:03:18.500: ERROR/AndroidRuntime(10367): FATAL EXCEPTION: main java.lang.RuntimeException: takePicture failed at android.hardware.Camera.native_takePicture(Native Method) at android.hardware.Camera.takePicture(Camera.java:1126) at android.hardware.Camera.takePicture(Camera.java:1071) at com.test.MotionDetector.CameraSurfaceView.onTouchEvent(CameraSurfaceView.java:107) at android.view.View.dispatchTouchEvent(View.java:7350) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2151) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1480) at android.app.Activity.dispatchTouchEvent(Activity.java:2469) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2099) at android.view.View.dispatchPointerEvent(View.java:7535) at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3492) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3424) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4534) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4512) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4616) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:125) at android.os.Looper.loop(Looper.java:124) at android.app.ActivityThread.main(ActivityThread.java:4921) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805) at dalvik.system.NativeStart.main(Native Method) 

我的代码:

 package com.nadim.MotionDetector; import android.content.Context; import android.hardware.Camera; import android.os.Environment; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.widget.Toast; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; private Context context; public CameraSurfaceView(Context context, Camera camera) { super(context); this.context = context; mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (IOException e) { Log.d("MotionDetector", "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // 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 (mHolder.getSurface() == null) { // preview surface does not exist return; } // stop preview before making changes try { mCamera.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 { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { Log.d("MotionDetector", "Error starting camera preview: " + e.getMessage()); } } @Override public boolean onTouchEvent(MotionEvent event) { Toast.makeText(context, "Picture taken", Toast.LENGTH_SHORT).show(); //System.gc(); tried this because it was suggested in a stackoverflow question but it didn't help. mCamera.takePicture(null, mPicture, mPicture); return true; //processed } private Camera.PictureCallback mPicture = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File pictureFile = getOutputMediaFile(); if (pictureFile == null) { return; } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); fos.close(); } catch (FileNotFoundException e) { Log.d("MotionDetector", "File not found: " + e.getMessage()); } catch (IOException e) { Log.d("MotionDetector", "Error accessing file: " + e.getMessage()); } } }; private static File getOutputMediaFile() { File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "motiondetect"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); File mediaFile; mediaFile = new File(mediaStorageDir, timeStamp + ".jpg"); return mediaFile; } } 

使用的权限和function:

      

我不知道崩溃发生的原因。 许多其他主题建议首先调用Camera.startPreview。 我这样做,但它没有解决问题。

LogCat拍照前:

 01-05 21:45:57.667: WARN/ActivityManager(754): No content provider found for permission revoke: file:///data/local/tmp/com.test.MotionDetector 01-05 21:45:57.667: WARN/ActivityManager(754): No content provider found for permission revoke: file:///data/local/tmp/com.test.MotionDetector 01-05 21:45:57.687: INFO/ActivityManager(754): Force stopping com.test.MotionDetector appid=10103 user=-1: uninstall pkg 01-05 21:45:57.687: INFO/ActivityManager(754): Killing 4264:com.test.MotionDetector/u0a103 (adj 7): stop com.test.MotionDetector 01-05 21:45:57.687: INFO/ActivityManager(754): Force finishing activity ActivityRecord{437a6678 u0 com.test.MotionDetector/.MotionDetectActivity t144} 01-05 21:45:57.697: WARN/InputDispatcher(754): channel '42adff40 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9 01-05 21:45:57.697: ERROR/InputDispatcher(754): channel '42adff40 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity (server)' ~ Channel is unrecoverably broken and will be disposed! 01-05 21:45:57.697: WARN/InputDispatcher(754): Attempted to unregister already unregistered input channel '42adff40 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity (server)' 01-05 21:45:57.697: INFO/WindowState(754): WIN DEATH: Window{42adff40 u0 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity} 01-05 21:45:57.757: INFO/PackageManager(754): Running dexopt on: com.test.MotionDetector 01-05 21:45:57.757: INFO/PackageManager(754): Package com.test.MotionDetector codePath changed from /data/app/com.test.MotionDetector-1.apk to /data/app/com.test.MotionDetector-2.apk; Retaining data and using new 01-05 21:45:57.807: INFO/ActivityManager(754): Force stopping com.test.MotionDetector appid=10103 user=-1: update pkg 01-05 21:45:57.807: WARN/PackageManager(754): Code path for pkg : com.test.MotionDetector changing from /data/app/com.test.MotionDetector-1.apk to /data/app/com.test.MotionDetector-2.apk 01-05 21:45:57.807: WARN/PackageManager(754): Resource path for pkg : com.test.MotionDetector changing from /data/app/com.test.MotionDetector-1.apk to /data/app/com.test.MotionDetector-2.apk 01-05 21:45:57.937: INFO/ActivityManager(754): Force stopping com.test.MotionDetector appid=10103 user=0: pkg removed 01-05 21:45:57.987: DEBUG/BackupManagerService(754): Received broadcast Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.test.MotionDetector flg=0x4000010 (has extras) } 01-05 21:45:58.047: DEBUG/BackupManagerService(754): Received broadcast Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.test.MotionDetector flg=0x4000010 (has extras) } 01-05 21:45:58.567: INFO/Icing.InternalIcingCorporaProvider(12750): Updating corpora: A: com.test.MotionDetector, C: MAYBE 01-05 21:45:58.647: DEBUG/PackageAddedReceiver(1086): package added com.test.MotionDetector 01-05 21:45:58.737: INFO/ActivityManager(754): START u0 {flg=0x10000000 cmp=com.test.MotionDetector/.MotionDetectActivity} from pid 4578 01-05 21:45:58.777: INFO/ActivityManager(754): Start proc com.test.MotionDetector for activity com.test.MotionDetector/.MotionDetectActivity: pid=4630 uid=10103 gids={50103, 1028, 1015} 01-05 21:45:59.627: INFO/ActivityManager(754): Displayed com.test.MotionDetector/.MotionDetectActivity: +861ms (total +972ms) 01-05 21:45:59.657: INFO/WindowManager(754): Screen frozen for +869ms due to Window{43cb77a8 u0 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity} 

假设您希望保存jpeg,则不需要原始回调,因此将调用更改为takePicture():

 mCamera.takePicture(null, mPicture, mPicture); 

 mCamera.takePicture(null, null, mPicture); 

在你的onTouchEvent()中。 这将使用jpeg图片回调。

调用takePicture()也会导致预览停止,因此如果要拍摄更多照片或重新开始预览,可能需要在onPictureTaken()回调中再次调用startPreview()。

此外,在onTouchEvent()中,您可能会收到多个事件,因此请筛选适合您的事件:

 @Override public boolean onTouchEvent(MotionEvent event) { Toast.makeText(context, "Picture taken", Toast.LENGTH_SHORT).show(); //System.gc(); tried this because it was suggested in a stackoverflow question but it didn't help. switch(event.getAction()) { case MotionEvent.ACTION_DOWN: // A pressed gesture has started, the motion contains the initial starting location break; case MotionEvent.ACTION_UP: // A pressed gesture has finished, the motion contains the final release location // as well as any intermediate points since the last down or move event. mCamera.takePicture(null, mPicture, mPicture); break; default: break; } return true; //processed } 

如果你在ACTION_DOWN中放置takePicture(),它会在你触摸屏幕时立即调用,而在ACTION_UP中,当你移开手指时它会发生。 看看哪一个适合你。