为什么在恢复CameraPreview时会发生NullPointerException?

时间:2016-05-27 21:16:40

标签: android nullpointerexception camera preview onresume

我的自定义相机实现适用于约95%的用户。 但是有些时候,当他们恢复相机预览活动后有一个NullPointerException,比如说从画廊中挑选照片(而不是拍摄实际照片),或者他们最小化应用程序,我不知道为什么,但即使相机实例在使用之前就已创建。

请查看我的代码(标记错误行如下:/ *第30行 - > * /)。

例外:

  

Android版本:android版本:4.4.4

     

这是我的自定义错误处理程序结果:java.lang.NullPointerException   在com.cerculdivelor.posting.CameraPreview。(CameraPreview.java:30)at   com.cerculdivelor.posting.CameraActivity.startCameraPreview(CameraActivity.java:130)   在   com.cerculdivelor.posting.CameraActivity.onResume(CameraActivity.java:99)   在   android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1199)   在android.app.Activity.performResume(Activity.java:5521)at   android.app.ActivityThread.performResumeActivity(ActivityThread.java:3046)   在   android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3085)   在   android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1325)   在android.os.Handler.dispatchMessage(Handler.java:102)at   android.os.Looper.loop(Looper.java:136)at   android.app.ActivityThread.main(ActivityThread.java:5584)at   java.lang.reflect.Method.invokeNative(Native Method)at   java.lang.reflect.Method.invoke(Method.java:515)at   com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:1268)   在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)at   dalvik.system.NativeStart.main(原生方法)

相机活动:

             @Override
                protected void onResume() {
                    super.onResume();
                        //Start the camera preview
                        if (Build.VERSION.SDK_INT >= 23) {
                            checkCameraPermissionFirst();
                        } else {
                            try {
                                startCameraPreview();
                            } catch(Exception e){
                                http.sendToServer(e);
                            }

                    }

                    //Check write permission, prompt the user to grant permission in case if SDK > 19 (Lolipop)
                    if (Build.VERSION.SDK_INT >= 23) {
                        checkWritePermissionFirst();
                    }
                }

                @Override
                protected void onPause() {
                    super.onPause();
                    Log.i("TAG", "PAUSED!!");
                    // TODO: kicsit veszelyes, figyelemmel kell kovetni!
                    //mCamera = null;

                }

                private void startCameraPreview() {
                    // Create an instance of Camera
                    mCamera = getCameraInstance();
                    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);

                    // remove any inital previews
                    //TODO: ezt azert figyelni kell meg!
                    preview.removeAllViews();

    /* line 130 -> */ mPreview = new CameraPreview(this, mCamera);
                    preview.addView(mPreview);
                }

  public static Camera getCameraInstance(Context context) {
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        } catch (Exception e) {
            // Camera is not available (in use or does not exist)
            Log.w("TAG", "Camera error: " + e);
            HttpConActivity http = new HttpConActivity(context);
            http.sendToServer(e);
        }
        return c; // returns null if camera is unavailable
    }

相机预览活动:

    package com.cerculdivelor.posting;

    import java.io.IOException;
    import java.util.List;

    import android.content.Context;
    import android.hardware.Camera;
    import android.hardware.Camera.Parameters;
    import android.hardware.Camera.Size;
    import android.util.Log;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

        private static final String TAG = "CameraPreview";

        private Context mContext;
        private SurfaceHolder mHolder;
        private Camera mCamera;
        private List<Size> mSupportedPreviewSizes;
        private Size mPreviewSize;

        public CameraPreview(Context context, Camera camera) {
            super(context);
            mContext = context;
            mCamera = camera;

              // supported preview sizes
/* line 30 -> */ mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            for(Size str: mSupportedPreviewSizes)
                    Log.e(TAG, "Preview sizes available: " + str.width + "/" + str.height);

            // 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) {
            // empty. surfaceChanged will take care of stuff
        }

        public void surfaceDestroyed(SurfaceHolder holder) {
            // empty. Take care of releasing the Camera preview in your activity.
             if (mCamera != null) {
                 mCamera.stopPreview();
                 mCamera.release();
                 mCamera = null;

                 Log.i("TAG", "Surface was distroyed.");
             }

        }

        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + 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
            if(mCamera != null) {
                try {
                    Parameters parameters = mCamera.getParameters();
                    parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

                    if (parameters.getSupportedFocusModes().contains(
                            Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                        parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                    }

                    mCamera.setParameters(parameters);
                    mCamera.setDisplayOrientation(90);
                    mCamera.setPreviewDisplay(mHolder);
                    mCamera.startPreview();

                } catch (Exception e) {
                    Log.d(TAG, "Error starting camera preview: " + e.getMessage());
                }
            }
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
            final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

            if (mSupportedPreviewSizes != null) {
                mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
            }

            float ratio;
            if(mPreviewSize.height >= mPreviewSize.width)
                ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
            else
                ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

            // One of these methods should be used, second method squishes preview slightly
            setMeasuredDimension(width, (int) (width * ratio));
    //        setMeasuredDimension((int) (width * ratio), height);
        }

        private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
            final double ASPECT_TOLERANCE = 0.1;
            double targetRatio = (double) h / w;

            if (sizes == null)
                return null;

            Size optimalSize = null;
            double minDiff = Double.MAX_VALUE;

            int targetHeight = h;

            for (Size size : sizes) {
                double ratio = (double) size.height / size.width;
                if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
                    continue;

                if (Math.abs(size.height - targetHeight) < minDiff) {
                    optimalSize = size;
                    minDiff = Math.abs(size.height - targetHeight);
                }
            }

            if (optimalSize == null) {
                minDiff = Double.MAX_VALUE;
                for (Size size : sizes) {
                    if (Math.abs(size.height - targetHeight) < minDiff) {
                        optimalSize = size;
                        minDiff = Math.abs(size.height - targetHeight);
                    }
                }
            }

            return optimalSize;
        }
    }

2 个答案:

答案 0 :(得分:0)

这可能是因为当应用程序在后台被销毁时mCamera正在丢失。你试过把相机实例放在课堂上吗?

 mCamera = camera;
if(mCamera==null)
{
   mCamera = getCameraInstance()
}

答案 1 :(得分:0)

在你的surfaceDestroyed中你将相机设置为null(mCamera = null;),然后当你的应用程序再次出现时,你的变量为null,请尝试使用surfaceCreated方法:

if (mCamera == null) {
    mCamera = Camera.open();
    mCamera.setPreviewDisplay(holder);
}