Android 相机应用程序:拍摄按钮不起作用?

Android Camera Application: Capture button not working?

我开发这个相机应用已经有一段时间了。基本上我想做的是拍照(并在内部存储),然后在下一个 Activity 中显示该图像。预览效果很好,但是当我点击 MainActivity 上的 Capture 按钮时,错误 "Unfortunately, myApplication has stopped" 出现并且应用程序崩溃了。 AndroidStudio 也不给我任何事件日志信息...

这是主要内容activity(SendInfo 有问题吗?):

public class MainActivity extends ActionBarActivity {
public final static String EXTRA_MESSAGE = "File_name";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Create an instance of Camera
    Camera mCamera = getCameraInstance();

    // Create our Preview view and set it as the content of our activity.
    CameraPreview mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview);

    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(R.id.button_capture);
    captureButton.setOnClickListener(new View.OnClickListener() {

       @Override
         public void onClick(View v) {
          Camera mCamera = getCameraInstance();
          // get an image from the camera
          mCamera.takePicture(null, null, mPicture);
         }
       }
    );
}
//////////////////////
public void sendInfo(View view)
{
    Intent intent = new Intent(this,show_image.class);
      Uri fileUri = getOutputMediaFileUri(1);
    intent.putExtra(EXTRA_MESSAGE, fileUri.toString());
    startActivity(intent);
}
/////////////////
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

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

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d("Logtag:", "Error creating media file, check storage permissions: "
                   );
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d("Logtag:", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("Logtag:", "Error accessing file: " + e.getMessage());
        }
    }
};


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
/** A safe way to get an instance of the Camera object. */
public 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)
        Toast.makeText(getApplicationContext(), "Camera is not available (in use or does not exist)",
                Toast.LENGTH_LONG).show();
    }
    return c; // returns null if camera is unavailable
}





public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
    return Uri.fromFile(getOutputMediaFile(type));
}


/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new     File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This locat ion works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("Logtag", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
                "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}
}

这是应该显示图像的第二个 Activity...

public class show_image extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent intent = getIntent();
    String stringURI = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
//    Uri uri = Uri.parse(stringURI);
   Bitmap bitmap = BitmapFactory.decodeFile(stringURI);
  ImageView imageView = new ImageView(this);
   imageView.setImageBitmap(bitmap);
    setContentView(imageView);


}

public static Bitmap decodeFile(File f, final int maxSize) {

    Bitmap b = null;
    // Decode image size
    BitmapFactory.Options o = new BitmapFactory.Options();
    o.inJustDecodeBounds = true;

    FileInputStream fis = null;
    try {
        fis = new FileInputStream(f);
        BitmapFactory.decodeStream(fis, null, o);
        fis.close();

        int scale = 1;
        if (o.outHeight > maxSize || o.outWidth > maxSize) {
            scale = (int) Math.pow(2, (int) Math.round(Math.log(maxSize / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;

        fis = new FileInputStream(f);
        b = BitmapFactory.decodeStream(fis, null, o2);

    } catch (Exception e) {
        Log.e("Logtag", "Error processing bitmap", e);
    } finally {
        //FileUtil.closeQuietly(fis);
    }

    return b;
}




@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
    }
}

日志猫的输出:

02-25 00:53:11.907  13191-13191/edu.ramapo.camer I/System.out﹕ debugger has settled (1480)

02-25 00:53:12.177  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.view.ViewGroup.onNestedScrollAccepted, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.onNestedScrollAccepted

02-25 00:53:12.177  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 11357: Landroid/view/ViewGroup;.onNestedScrollAccepted (Landroid/view/View;Landroid/view/View;I)V

02-25 00:53:12.177  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0000

02-25 00:53:12.177  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.view.ViewGroup.onStopNestedScroll, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.onStopNestedScroll

02-25 00:53:12.177  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 11363: Landroid/view/ViewGroup;.onStopNestedScroll (Landroid/view/View;)V

02-25 00:53:12.177  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6f at 0x0000

02-25 00:53:12.177  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.support.v7.internal.widget.ActionBarOverlayLayout.stopNestedScroll, referenced from method android.support.v7.internal.widget.ActionBarOverlayLayout.setHideOnContentScrollEnabled

02-25 00:53:12.177  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 9047: Landroid/support/v7/internal/widget/ActionBarOverlayLayout;.stopNestedScroll ()V

02-25 00:53:12.177  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x000e

02-25 00:53:12.207  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.internal.widget.TintTypedArray.getChangingConfigurations

02-25 00:53:12.207  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 365: Landroid/content/res/TypedArray;.getChangingConfigurations ()I

02-25 00:53:12.207  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002

02-25 00:53:12.207  13191-13191/edu.ramapo.camer I/dalvikvm﹕ Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.internal.widget.TintTypedArray.getType

02-25 00:53:12.207  13191-13191/edu.ramapo.camer W/dalvikvm﹕ VFY: unable to resolve virtual method 387: Landroid/content/res/TypedArray;.getType (I)I

02-25 00:53:12.207  13191-13191/edu.ramapo.camer D/dalvikvm﹕ VFY: replacing opcode 0x6e at 0x0002

02-25 00:53:13.068  13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libEGL_adreno200.so

02-25 00:53:13.068  13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libGLESv1_CM_adreno200.so

02-25 00:53:13.078  13191-13191/edu.ramapo.camer D/libEGL﹕ loaded /system/lib/egl/libGLESv2_adreno200.so

02-25 00:53:13.078  13191-13191/edu.ramapo.camer I/Adreno200-EGL﹕ <qeglDrvAPI_eglInitialize:265>: EGL 1.4 QUALCOMM build: HAREESHG_Nondeterministic_AU+PATCH[ES]_msm8960_JB_1.9.6_MR2_CL3219408_release_ENGG (CL3219408)
    Build Date: 09/28/13 Sat
    Local Branch: hhh
    Remote Branch: quic/jb_1.9.6_1
    Local Patches: 8d50ec23e42ef52b570aa6ff1650afac0b503d78 CL3219408: Fix in the Glreadpixels for negative offsets and larger dimensions.
    801859126f6ca69482b39a34ca61447e3f7cded8 rb: fix panel settings to clear undrawn/undefined buffers
    Reconstruct Branch: LOCAL_PATCH[ES]

02-25 00:53:13.118  13191-13191/edu.ramapo.camer D/OpenGLRenderer﹕ Enabling debug mode 0

02-25 00:53:27.353  13191-13191/edu.ramapo.camer D/Logtag﹕ failed to create directory

02-25 00:53:27.353  13191-13191/edu.ramapo.camer D/Logtag:﹕ Error creating media file, check storage permissions:

我认为崩溃的原因是因为您试图两次获取相机实例:创建 activity 时以及按下按钮 captureButton 时。当您第二次尝试获取它时,它 returns null 因为它已被您的 activity.

使用

您应该在按下 captureButton 按钮之前获取一次相机实例,然后处理之后拍摄的照片。

public class MainActivity extends ActionBarActivity {
  public final static String EXTRA_MESSAGE = "File_name";
  private Camera mCamera; 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      // Create an instance of Camera
      mCamera = getCameraInstance();

      // Create our Preview view and set it as the content of our activity.
      CameraPreview mPreview = new CameraPreview(this, mCamera);
      FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
      preview.addView(mPreview);

      // Add a listener to the Capture button
      Button captureButton = (Button) findViewById(R.id.button_capture);
      captureButton.setOnClickListener(new View.OnClickListener() {

         @Override
           public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, mPicture);
           }
         }
      );
  }

  ...

编辑

拍照时要移动到下一张activity,可以在Camera.PictureCallback之后调用startActivity 已将 byte 数组保存到文件中。

private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

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

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d("Logtag:", "Error creating media file, check storage permissions: "
                   );
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();

            Intent intent = new Intent(this,show_image.class);
            Uri fileUri = Uri.fromFile(pictureFile);
            intent.putExtra(EXTRA_MESSAGE, fileUri.toString());
            startActivity(intent);

        } catch (FileNotFoundException e) {
            Log.d("Logtag:", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("Logtag:", "Error accessing file: " + e.getMessage());
        }
    }
};

...

编辑 2

您需要将此权限添加到清单中才能将照片存储在设备上:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

希望对您有所帮助。