Android camera API app crashes at onResume

2019-04-30 04:09发布

问题:

I am using camera API to write an app: show preview, and take a photo. The first version works very well. In class Preview extends SurfaceView implements SurfaceHolder.Callback

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, acquire the camera and tell it where
    // to draw.
    camera = Camera.open();
    try {
        camera.setPreviewDisplay(holder);
        camera.startPreview();

    } catch (IOException e) {
        e.printStackTrace();
    }

    hasSurface = true;
}


public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // It will be called immediately after surfaceCreated
    // I move it to Resume.
    setCameraPreviewParameters();

    camera.startPreview();

}

In the main activity:

public class CameraDemo extends Activity

I also set a member: CameraUnit ui; It is:

public class CameraUnit extends LinearLayout

In the onCreate,

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ui = new CameraUnit(this);
    setContentView((View) ui); 

    Log.d(TAG, "onCreate'd");
}

it create a LinearLayout object, which contains the surfaceView, and a camera button.

The onResume is:

    @Override
protected void onResume() {
    super.onResume();
}

Although it works, I think the onResume shouldn't be empty. I also see the surfaceCreated and surfaceChanged are empty in a famous Android app example OCRTest So I believe it is better and also feasible to move the commands in surfaceCreated and surfaceChanged to onResume.

I think the flow chat for the 1st Version of my app should be: Main activity onCreate (where the LinearLayout and its surfaceView, camera button are created), surfaceCreated and surfaceChanged are called, onResume.

So I may simply move the commands in surfaceCreated and surfaceChanged to onResume. But it doesn't work! I used Debug to find out the surface is null. I think the surfaceCreatd is not called. My app is different OCRTest, which implements SurfaceHolder.Callback in the main activity. I implement SurfaceHolder.Callback in the SurfaceView:

class Preview extends SurfaceView implements SurfaceHolder.Callback

So I add two other lines in onResume

        ui.preview.surfaceCreated(ui.preview.mHolder);
    ui.preview.surfaceChanged(ui.preview.mHolder, 0, 800, 400);

I randomly set the last three integer arguments. When I start the activity, the error window in Android phone pops out. It says “Caused by: java.lang.RuntimeException: Fail to connect to camera service”. But how to fix it???? Thanks a lot!

Errors are:

    01-07 00:27:57.173: W/dalvikvm(11625): threadid=1: thread exiting with uncaught exception (group=0x4001d5a0)
01-07 00:27:57.173: E/AndroidRuntime(11625): FATAL EXCEPTION: main
01-07 00:27:57.173: E/AndroidRuntime(11625): java.lang.RuntimeException: Unable to resume activity {com.example/com.example.CameraDemo}: java.lang.RuntimeException: Fail to connect to camera service
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2460)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2481)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1847)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread.access$1500(ActivityThread.java:132)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1038)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.os.Handler.dispatchMessage(Handler.java:99)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.os.Looper.loop(Looper.java:150)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread.main(ActivityThread.java:4263)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at java.lang.reflect.Method.invokeNative(Native Method)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at java.lang.reflect.Method.invoke(Method.java:507)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at dalvik.system.NativeStart.main(Native Method)
01-07 00:27:57.173: E/AndroidRuntime(11625): Caused by: java.lang.RuntimeException: Fail to connect to camera service
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.hardware.Camera.native_setup(Native Method)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.hardware.Camera.<init>(Camera.java:265)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.hardware.Camera.open(Camera.java:241)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at com.example.Preview.surfaceCreated(Preview.java:60)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at com.example.CameraDemo.onResume(CameraDemo.java:64)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1242)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.Activity.performResume(Activity.java:3904)
01-07 00:27:57.173: E/AndroidRuntime(11625):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2450)
01-07 00:27:57.173: E/AndroidRuntime(11625):    ... 12 more
01-07 00:27:59.455: I/Process(11625): Sending signal. PID: 11625 SIG: 9

回答1:

You get this

java.lang.RuntimeException: Fail to connect to camera service

Exception, when the Camera is being used by other applications. But i believe that other application is your application itself. You have to release the Camera.

These are the cases where you should release the Camera:

In the Preview class:

public void surfaceDestroyed(SurfaceHolder holder) {

    // empty. Take care of releasing the Camera preview in your activity.
    if (mCamera != null) {
        mCamera.release();
    }
}

In the Activity:

@Override
public void onBackPressed() {
    super.onBackPressed();
    if (myCamera != null) {
        myCamera.release();
    }
    finish();
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    if (myCamera != null) {
        myCamera.release();
    }
}

Also on Cancel clicked, and also when you are finished using the Camera i.e.., when the Image is Captured and you come back to the Activity.

Also try this:

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    if (mHolder.getSurface() == null) {
        return;
    }

    try {
        mCamera.stopPreview();
    } catch (Exception e) {
        //You can ignore this, because this means the Preview doesn't Exist
        //So, no need to try stopping
    }

    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        //Catch this
    }
}


回答2:

So I Created an app that used the camera but a different Launch Icon to get to the settings page. So Every time i paused and minimised the app to change the settings and went back it also crashed with this Error. So after a lot of research I still had no answer. Then i realised this had to do with the Managing of the Life Cycle of the Camera. So went and looked at the Life Cycle, specifically at Pausing. So i Realised, we are all doing this on the wrong method. Where we are doing it on the onResume, we should be doing it onStart. AND BAM! it worked.

Here is my code for my app.

@Override
    protected void onPause() {
        super.onPause();
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
        if (mPreview != null) {
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_viewer);
            preview.removeView(mPreview);
            mPreview = null;
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
        if (mPreview != null) {
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_viewer);
            preview.removeView(mPreview);
            mPreview = null;
        }
    }
    @Override
    protected void onResume() {
        super.onResume();

    }

    @Override
    protected void onStart(){
        super.onStart();
//Check if the camera exists or not so it does not clash with the onCreate
        if(mCamera == null){
            dir_string =  new File("/storage/sdcard1/app");
            Log.d("TAG",dir_string.toString());
            mCamera = getCameraInstance();
            mPreview = new CameraPreview(this, mCamera);
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_viewer);
            preview.addView(mPreview);
        }
    }

Hope this help someone at least.



回答3:

I find in some examples, the camera open code is included both in the surfaceChanged, and in the onResume, using an if sentence to avoid repetition. Maybe this is one way to solve the problem.