【问题标题】:Why does a NullPointerException happen when resuming CameraPreview?为什么恢复 CameraPreview 时会发生 NullPointerException?
【发布时间】:2016-05-28 19:25:49
【问题描述】:

我的自定义相机实现适用于大约 95% 的用户。 但是有时在他们恢复相机预览活动后会出现 NullPointerException,比如从图库中挑选照片(而不是拍摄实际照片),或者他们最小化应用程序,我不知道为什么,但即使发生这种情况相机实例是在使用它之前创建的。

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

例外:

安卓版本:安卓版本:4.4.4

这是我的自定义错误处理程序结果:java.lang.NullPointerException 在 com.cerculdivivelor.posting.CameraPreview.(CameraPreview.java:30) 在 com.cerculdivivelor.posting.CameraActivity.startCameraPreview(CameraActivity.java:130) 在 com.cerculdivor.posting.CameraActivity.onResume(CameraActivity.java:99) 在 android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1199) 在 android.app.Activity.performResume(Activity.java:5521) 在 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) 在 android.os.Looper.loop(Looper.java:136) 在 android.app.ActivityThread.main(ActivityThread.java:5584) 在 java.lang.reflect.Method.invokeNative(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:515) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084) 在 dalvik.system.NativeStart.main(Native Method)

相机活动:

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

【问题讨论】:

  • 你的 startCameraPreview 是从哪里调用的?
  • @TomerShemesh,在 onResume 中。谢谢

标签: android nullpointerexception camera preview onresume


【解决方案1】:

这可能是因为当应用程序在后台被破坏时,mCamera 正在丢失。您是否尝试过在类中直接获取相机实例?

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

【讨论】:

  • 对不起,首先我忘了发布 getCameraInstance() 块。我已经更新了我的问题,您可以在相机活动部分的末尾看到它。无论如何,正如文档所说,我在这里初始化 Camera ( c = Camera.open() ) 。 :(
【解决方案2】:

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

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

【讨论】:

  • 请看我的getCameraInstance()(在上面的Camera Activity末尾),抱歉没有早点发布。在这里我做 Camera.open() - 正如官方文档所说。它还说在暂停时我每次都必须释放它。
猜你喜欢
  • 1970-01-01
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多