Android:java.lang.RuntimeException:takePicture失败 [英] Android: java.lang.RuntimeException: takePicture failed

查看:165
本文介绍了Android:java.lang.RuntimeException:takePicture失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Surfaceview的触摸事件中捕获图像。但是,每次触摸屏幕时,应用程序都会崩溃,并出现以下异常:

I'm am trying to capture an image in the ontouchevent of surfaceview. However, everytime a touch the screen, the app crashes with the following 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;
    }
}

使用的权限和功能:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />

我不知道崩溃发生的原因。许多其他主题建议先调用Camera.startPreview。我正在这样做,但是并不能解决问题。

I don't know why the crash occurs. Many other topic suggest calling Camera.startPreview first. I am doing that, but it doesn't solve the issue.

LogCat拍照前:

LogCat before taking picture:

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()的调用更改为:

Assuming that you want the jpeg saved, you don't need raw callback, so change the call to takePicture() from:

mCamera.takePicture(null, mPicture, mPicture);

mCamera.takePicture(null, null, mPicture);

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

in your onTouchEvent(). This will use jpeg picture callback.

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

Calling takePicture() also causes the preview to stop, so you might want to call startPreview() again in your onPictureTaken() callback, if you want to take more pictures or have a preview restarted.

此外,在您的onTouchEvent()中,您可能会遇到多个事件,因此请过滤一个适合您的事件:

Also, in your onTouchEvent(), you might be getting multiple events, so filter for the one that works for you:

@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
}

如果将takePicture()放在ACTION_DOWN中,它将被调用只需触摸屏幕即可,而在ACTION_UP中,移开手指就会发生这种情况。看看哪一种适合您。

If you place takePicture() in ACTION_DOWN, it will be called as soon as you touch the screen, whereas when in ACTION_UP, it will happen when you remove finger. See which one works for you.

这篇关于Android:java.lang.RuntimeException:takePicture失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆