Search code examples
androidandroid-camerasurfaceviewsurfaceholder

Android custom camera app retake often crashes


I am developing my own custom camera app,while running the application if I click the capture button my camera will capture the current position.what I actually need is retaking a photo whenever I need.But if I click the retake(take photo) button the app will crash.Here I attached my code below.So any one please help me to resolve the error.

MainActivity.java

package com.example.camera1;



import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends Activity {

       private Camera cameraObject;
       private ShowCamera showCamera;
       private ImageView pic;
       private Button takePhotoButton;
       public static Camera isCameraAvailiable(){
          Camera object = null;
          try {

             object = Camera.open(); 
          }
          catch (Exception e){
          }
          return object; 
       }

       private PictureCallback capturedIt = new PictureCallback() {

          @Override
          public void onPictureTaken(byte[] data, Camera camera) {

          Bitmap bitmap = BitmapFactory.decodeByteArray(data , 0, data .length);
          if(bitmap==null){
             Toast.makeText(getApplicationContext(), "not taken", Toast.LENGTH_SHORT).show();
          }
          else
          {
             Toast.makeText(getApplicationContext(), "taken", Toast.LENGTH_SHORT).show();       
          }
          cameraObject.release();
       }
    };

       @Override
       protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);    
          takePhotoButton = (Button)findViewById(R.id.button_takephoto);
          cameraObject = isCameraAvailiable();
          showCamera = new ShowCamera(this, cameraObject);
          FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
          preview.addView(showCamera);



          takePhotoButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                  cameraObject = isCameraAvailiable();

                  cameraObject.stopPreview();
                    showCamera = new ShowCamera(getApplicationContext(), cameraObject);
                      FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
                      preview.addView(showCamera);
            }
        });

       }
       public void snapIt(View view){
          cameraObject.takePicture(null, null, capturedIt);
       }

       @Override
       public void onPause(){
           super.onPause();
       }

       @Override
       public boolean onCreateOptionsMenu(Menu menu) {
          getMenuInflater().inflate(R.menu.activity_main, menu);
          return true;
       }
    }

ShowCamera.java

package com.example.camera1;

import java.io.IOException;

import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class ShowCamera extends SurfaceView implements SurfaceHolder.Callback {

       private SurfaceHolder holdMe;
       private Camera theCamera;

       public ShowCamera(Context context,Camera camera) {
          super(context);
          theCamera = camera;
          holdMe = getHolder();
          holdMe.addCallback(this);
       }

       @Override
       public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
       }

       @Override
       public void surfaceCreated(SurfaceHolder holder) {
          try   {
              theCamera.setDisplayOrientation(90);
             theCamera.setPreviewDisplay(holder);
             theCamera.startPreview(); 
          } catch (IOException e) {
          }
       }

       @Override
       public void surfaceDestroyed(SurfaceHolder arg0) {

           theCamera.stopPreview(); 
       }

    }

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="horizontal" >

   <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_weight="0.30"
      android:orientation="vertical" >

         <FrameLayout
            android:id="@+id/camera_preview"
            android:layout_width="fill_parent"
            android:layout_height="350dp" />

         <RelativeLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content" >

             <Button
                 android:id="@+id/button_capture"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:onClick="snapIt"
                 android:text="@string/Capture" />

             <Button
                 android:id="@+id/button_takephoto"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_below="@+id/button_capture"
                 android:text="Take Photo" />
         </RelativeLayout>

   </LinearLayout>

</LinearLayout>

Solution

  • I think the reason is you called cameraObject.release(); in onPictureTaken. You can remove it. And, don't forget to call startPreview() again.

    Because:

    This method is only valid when preview is active (after startPreview()). Preview will be stopped after the image is taken; callers must call startPreview() again if they want to re-start preview or take more pictures. This should not be called between start() and stop().

    After calling this method, you must not call startPreview() or take another picture until the JPEG callback has returned.