安卓自定义相机在恢复时崩溃

4

我在我的应用程序中有一个自定义相机活动,它运行良好,但是当我在相机活动中按下主页按钮,然后返回到应用程序时,它会崩溃,并且logcat显示在surface view创建时出现了空指针异常。这个setup方法在onResume中被调用:

    public void setup()
    {

    preview = new CameraPreview(this);
    ((FrameLayout) findViewById(R.id.camera_preview)).addView(preview);
    head=(ImageView)findViewById(R.id.head);
        head.setX((float)(Shared.screenWidth/5*1.8));
        head.setY((float)(Shared.screenHeight*0.03));
        LayoutParams params = (LayoutParams) head.getLayoutParams();
        params.width = (int)((Shared.screenWidth/5*3.2)-(head.getX()));
        params.height=(int)((Shared.screenHeight/3.8)-(head.getY()));
        head.setLayoutParams(params);
    body=(ImageView)findViewById(R.id.body);
        body.setX((float)(Shared.screenWidth/7));
        body.setY((float)(Shared.screenHeight/3.8));
        LayoutParams params2 = (LayoutParams) body.getLayoutParams();
        params2.width = (int)((Shared.screenWidth/7*6)-(body.getX()));
        params2.height=(int)((Shared.screenHeight)-(body.getY()));
        body.setLayoutParams(params2);
    go=(Button)findViewById(R.id.go);
    again=(Button)findViewById(R.id.again);
    stop=(ImageButton)findViewById(R.id.stop);
    stop.setOnClickListener( new OnClickListener() {
        public void onClick(View v) {
            Intent i =new Intent(CamActivity.this,Main.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
            startActivity(i);


        }
    });
    btn = (ImageButton) findViewById(R.id.takePic);
    btn.setOnClickListener( new OnClickListener() {
        public void onClick(View v) {
            preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            btn.setVisibility(View.INVISIBLE);
            btn.setEnabled(false);
            go.setVisibility(View.VISIBLE);
            go.setEnabled(true);
            head.setVisibility(View.INVISIBLE);
            body.setVisibility(View.INVISIBLE);
            go.setOnClickListener( new OnClickListener() {
                public void onClick(View v) {
                    Shared.bm=Bitmap.createScaledBitmap(bmp, Shared.screenWidth, Shared.screenHeight, true);

                    Intent i=new Intent(CamActivity.this,IKill.class);
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
                    startActivity(i);

                }
            });
            again.setVisibility(View.VISIBLE);
            again.setEnabled(true);
            again.setOnClickListener( new OnClickListener() {
                public void onClick(View v) {
                    if (Build.VERSION.SDK_INT >= 11) {
                        recreate();
                    } else {
                        Intent intent = getIntent();
                        overridePendingTransition(0, 0);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                        finish();

                        overridePendingTransition(0, 0);
                        startActivity(intent);
                    }

                }
            });

        }
    });


}

此外,在我的onCreate方法中,我也有以下代码:
requestWindowFeature(Window.FEATURE_NO_TITLE);

    // hide status bar
    final Window win = getWindow();
    win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
              WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.activity_camera);

以及logcat:

08-23 08:56:20.174: E/AndroidRuntime(835): FATAL EXCEPTION: main
08-23 08:56:20.174: E/AndroidRuntime(835): java.lang.NullPointerException
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
com.example.i_kill.CameraPreview.surfaceCreated(CameraPreview.java:38)
08-23 08:56:20.174: E/AndroidRuntime(835):  at   
android.view.SurfaceView.updateWindow(SurfaceView.java:569)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.SurfaceView.access$000(SurfaceView.java:86)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.SurfaceView$3.onPreDraw(SurfaceView.java:174)
08-23 08:56:20.174: E/AndroidRuntime(835):  at   
android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:680)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1842)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.Choreographer.doCallbacks(Choreographer.java:562)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.Choreographer.doFrame(Choreographer.java:532)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.os.Handler.handleCallback(Handler.java:725)
08-23 08:56:20.174: E/AndroidRuntime(835):  at   
android.os.Handler.dispatchMessage(Handler.java:92)
08-23 08:56:20.174: E/AndroidRuntime(835):  at android.os.Looper.loop(Looper.java:137)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
android.app.ActivityThread.main(ActivityThread.java:5041)
08-23 08:56:20.174: E/AndroidRuntime(835):  at   
java.lang.reflect.Method.invokeNative(Native Method)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
java.lang.reflect.Method.invoke(Method.java:511)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
08-23 08:56:20.174: E/AndroidRuntime(835):  at 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
08-23 08:56:20.174: E/AndroidRuntime(835):  at dalvik.system.NativeStart.main(Native  
Method)
08-23 08:56:26.065: E/Trace(909): error opening trace file: No such file or directory 

以下是整个类的代码:

包名:com.example.i_kill;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;


public class CamActivity extends Activity {
public static final int MEDIA_TYPE_IMAGE = 1;
public static String TAG="MainActivity";
private static Camera camera;
private CameraPreview preview;
private ImageView head,body;
private ImageButton btn, stop;
private Button again,go;
private Bitmap bmp;
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    // hide status bar
    final Window win = getWindow();
    win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
              WindowManager.LayoutParams.FLAG_FULLSCREEN);
    setContentView(R.layout.activity_camera);

}
    public void setup()
    {

    preview = new CameraPreview(this);
    ((FrameLayout) findViewById(R.id.camera_preview)).addView(preview);
    head=(ImageView)findViewById(R.id.head);
        head.setX((float)(Shared.screenWidth/5*1.8));
        head.setY((float)(Shared.screenHeight*0.03));
        LayoutParams params = (LayoutParams) head.getLayoutParams();
        params.width = (int)((Shared.screenWidth/5*3.2)-(head.getX()));
        params.height=(int)((Shared.screenHeight/3.8)-(head.getY()));
        head.setLayoutParams(params);
    body=(ImageView)findViewById(R.id.body);
        body.setX((float)(Shared.screenWidth/7));
        body.setY((float)(Shared.screenHeight/3.8));
        LayoutParams params2 = (LayoutParams) body.getLayoutParams();
        params2.width = (int)((Shared.screenWidth/7*6)-(body.getX()));
        params2.height=(int)((Shared.screenHeight)-(body.getY()));
        body.setLayoutParams(params2);
    go=(Button)findViewById(R.id.go);
    again=(Button)findViewById(R.id.again);
    stop=(ImageButton)findViewById(R.id.stop);
    stop.setOnClickListener( new OnClickListener() {
        public void onClick(View v) {
            Intent i =new Intent(CamActivity.this,Main.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
            startActivity(i);


        }
    });
    btn = (ImageButton) findViewById(R.id.takePic);
    btn.setOnClickListener( new OnClickListener() {
        public void onClick(View v) {
            preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            btn.setVisibility(View.INVISIBLE);
            btn.setEnabled(false);
            go.setVisibility(View.VISIBLE);
            go.setEnabled(true);
            head.setVisibility(View.INVISIBLE);
            body.setVisibility(View.INVISIBLE);
            go.setOnClickListener( new OnClickListener() {
                public void onClick(View v) {
                    Shared.bm=Bitmap.createScaledBitmap(bmp, Shared.screenWidth, Shared.screenHeight, true);

                    Intent i=new Intent(CamActivity.this,IKill.class);
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
                    startActivity(i);

                }
            });
            again.setVisibility(View.VISIBLE);
            again.setEnabled(true);
            again.setOnClickListener( new OnClickListener() {
                public void onClick(View v) {
                    if (Build.VERSION.SDK_INT >= 11) {
                        recreate();
                    } else {
                        Intent intent = getIntent();
                        overridePendingTransition(0, 0);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                        finish();

                        overridePendingTransition(0, 0);
                        startActivity(intent);
                    }

                }
            });

        }
    });


}

ShutterCallback shutterCallback = new ShutterCallback() {
    public void onShutter() {
        Log.d(TAG, "onShutter'd");
    }
};

PictureCallback rawCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
        Log.d(TAG, "onPictureTaken - raw");
    }
};

/** Handles data for jpeg picture */
PictureCallback jpegCallback = new PictureCallback() {
    public void onPictureTaken(byte[] data, Camera camera) {
        bmp=BitmapFactory.decodeByteArray(data, 0, data.length );
        System.out.println(bmp.getHeight());
        System.out.println(bmp.getWidth());
};
};


public void onPause(){
super.onPause();
if(camera!=null){
    camera.stopPreview();
    camera.setPreviewCallback(null);

    camera.release();
    camera = null;
}


}


public void onResume()
 {
super.onResume();
setup();
    }
}

相机预览类:

package com.example.i_kill;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
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 SurfaceHolder holder;
public Camera camera;
public static String TAG="CameraPreview";
public CameraPreview(Context context) {
    super(context);

    holder=getHolder();
    holder.addCallback(this);
    holder.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.

camera = getCameraInstance();

  try {

        camera.setPreviewDisplay(holder);
camera.setPreviewCallback(new PreviewCallback() {

    public void onPreviewFrame(byte[] data, Camera arg1) {
        FileOutputStream outStream = null;
        try {
            outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));  
            outStream.write(data);
            outStream.close();
            Log.d(TAG, "onPreviewFrame - wrote bytes: " + data.length);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
            CameraPreview.this.invalidate();
    }
});
   } catch (IOException e) {
e.printStackTrace();
}

}

public void surfaceDestroyed(SurfaceHolder holder) {

if(camera!=null){
    camera.stopPreview();
    camera.setPreviewCallback(null);

    camera.release();
    camera = null;
}

}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Camera.Parameters parameters = camera.getParameters();
  List<Size> previewSizes = parameters.getSupportedPreviewSizes();
  Size bestSize = null;
  int bestDiff = 0;
 int diff = 0;
  for (Size size : previewSizes) {
      diff = Math.abs(h - size.height) + Math.abs(w - size.width);
  if (bestSize == null || diff < bestDiff) {
          bestSize = size;
          bestDiff = diff;
  }
  parameters.setPreviewSize(bestSize.width, bestSize.height);
  camera.setParameters(parameters);
  }

      //start preview of camera
camera.startPreview();
}

@Override
public void draw(Canvas canvas) {
    super.draw(canvas);
    Paint p= new Paint(Color.RED);
    Log.d(TAG,"draw");
    canvas.drawText("PREVIEW", canvas.getWidth()/2, canvas.getHeight()/2, p );
}

private Camera getCameraInstance(){
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)
}
return c; // returns null if camera is unavailable
}
}

感谢您的帮助 :)。

你能在这里发布你的完整类吗? - Piyush
我一会儿就贴上来,这里的缩进出了问题,我完全不知道为什么... - Misha
问题在于您没有在暂停时释放相机。您需要调用preview.camera.stopPreview(); preview.camera.release和preview.camera = null。另外,请分享CameraPreview类的代码。 - sanky jain
你需要在cameraPreview类中释放它,而不是在onPause方法中释放。创建一个名为public void surfaceDestroyed(SurfaceHolder holder)的方法,并将释放代码添加到它中,在cameraPreview类中实现。 - sanky jain
@Meshi 这里我有一个疑问.. - Piyush
显示剩余5条评论
3个回答

5

我通过在恢复时调用setContentView来解决了这个问题。谢谢大家!


我只是想告诉你同样的事情,但在此之前你已经解决了...太棒了...!! - Piyush
这帮助我解决了应用程序崩溃的问题。但是,我需要添加 Gilberto Ibarra 答案中提到的内容,以确保我的相机预览显示任何内容。 ;) - spoko

4
这是我的解决方案。
public void onResume(){
    super.onResume();

    if(mCamera ==null){

    setContentView(R.layout.activity_capture_local_plates);     
    autoFocusHandler = new Handler();
    mCamera = getCameraInstance();       

    mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
    FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
    preview.addView(mPreview);

    }

}

1
已解决!虽然你的答案并不是这个问题的真正解决方案,但我正在寻找这个并且发现你的答案是我所面临问题的解决方案。谢谢。+1 - Rafique Mohammed
我的解决方案是在onResume中重新加载布局...这样相机就不会崩溃了。 - Gilberto Ibarra

0

在 surfaceCreated 中调用 getHolder() 是否更合适?在文档中找到以下内容:

可以通过 SurfaceHolder 接口访问底层表面,可以通过调用 getHolder() 来检索它。

当 SurfaceView 窗口可见时,Surface 将为您创建;您应该实现 surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)来发现 Surface 何时随着窗口的显示和隐藏而创建和销毁。


实际上它并没有!但表面是黑色的,虽然很遗憾 :( - Misha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接