Android crashing after camera Intent

2019-01-16 11:39发布

I have an app published and one of the fundamental features is to allow the user to take a picture, and then save that photo in a specific folder on their External Storage.

Everything seems to be working fine, but I've gotten two reports now that claim that after taking a photo, and clicking "Done" to exit the camera (and return back to the Activity), the app is Forced Closed, bringing the user back to the home screen.

This happens on a Samsung Nexus S and the Galaxy Tab. Below I've posted my code to show I set up my intent and how I handle saving and displaying the photo in onActivityResult(). Any guidance on what might be causing it to crash after they click "Done" to exit the camera app, would be greatly appreciated!

Again, this seems to be working fine on most devices but I was wondering if their is a more efficient, universal approach I should be taking. Thank you

How I'm firing the Camera Intent

   case ACTION_BAR_CAMERA:

        // numbered image name
        fileName = "image_" + String.valueOf(numImages) + ".jpg";


        output = new File(direct + File.separator + fileName); // create
                                                                    // output
        while (output.exists()) { // while the file exists
            numImages++; // increment number of images
            fileName = "image_" + String.valueOf(numImages) + ".jpg";
            output = new File(outputFolder, fileName);


        }
        camera = new   Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        uriSavedImage = Uri.fromFile(output); // get Uri of the output
        camera.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage); //pass in Uri to camera intent
        startActivityForResult(camera, 1);


        break;
    default:
        return super.onHandleActionBarItemClick(item, position);
    }
    return true;
}

How I'm setting up onActivityResult()

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) { // If data was passed successfully

        Bundle extras = data.getExtras();

        //Bundle extras = data.getBundleExtra(MediaStore.EXTRA_OUTPUT);

        /*ad = new AlertDialog.Builder(this).create();
        ad.setIcon(android.R.drawable.ic_menu_camera);
        ad.setTitle("Save Image");
        ad.setMessage("Save This Image To Album?");
        ad.setButton("Ok", this);

        ad.show();*/



        bmp = (Bitmap) extras.get("data"); // Set the bitmap to the bundle
                                            // of data that was just
                                            // received
        image.setImageBitmap(bmp); // Set imageview to image that was
                                    // captured
        image.setScaleType(ScaleType.FIT_XY);


    }

}

7条回答
放荡不羁爱自由
2楼-- · 2019-01-16 12:08

Follow the steps given on this link. Hope this is useful for you.

OR

Fetching Your Image Without Crashing

Write the below code in MainActivity

// Storage for camera image URI components 
private final static String CAPTURED_PHOTO_PATH_KEY = "mCurrentPhotoPath";      
private final static String CAPTURED_PHOTO_URI_KEY = "mCapturedImageURI"; 

// Required for camera operations in order to save the image file on resume.    
private String mCurrentPhotoPath = null; 
private Uri mCapturedImageURI = null; 

@Override 
public void onSaveInstanceState(Bundle savedInstanceState) { 
   if (mCurrentPhotoPath != null) {            
     savedInstanceState.putString(CAPTURED_PHOTO_PATH_KEY, mCurrentPhotoPath); 
   } 
  if (mCapturedImageURI != null) {  
     savedInstanceState.putString(CAPTURED_PHOTO_URI_KEY, mCapturedImageURI.toString()); 
  } 
  super.onSaveInstanceState(savedInstanceState); 
} 

@Override 
protected void onRestoreInstanceState(Bundle savedInstanceState) {

   if (savedInstanceState.containsKey(CAPTURED_PHOTO_PATH_KEY)) {
       mCurrentPhotoPath = savedInstanceState.getString(CAPTURED_PHOTO_PATH_KEY); 
   } 
   if (savedInstanceState.containsKey(CAPTURED_PHOTO_URI_KEY)) {
   mCapturedImageURI = Uri.parse(savedInstanceState.getString(CAPTURED_PHOTO_URI_KEY)); 
   } 
   super.onRestoreInstanceState(savedInstanceState); 
}
查看更多
神经病院院长
3楼-- · 2019-01-16 12:13

First, make sure to check request code, you might be catching someone else's result there. Second, don't use the intent's data Bitmap - if anything, it's small, but since you provide the path to store captured image, it shouldn't even be there (see here). So, store the url you provided as output file path and read Bitmap from there when you've received RESULT_OK for your request:

    ...
    // save your file uri, not necessarily static
    mUriSavedImage = Uri.fromFile(output);
    startActivityForResult(camera, MY_REQUEST_CODE);
    /* Make a String like "com.myname.MY_REQUEST_CODE" and hash it into int to give it
    a bit of uniqueness */
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == MY_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
             Bitmap bmp = BitmapFactory.decodeFile(mUriSavedImage);
             if (bmp != null) {
                 image.setImageBitmap(bmp); // Set imageview to image that was
                                // captured
                 image.setScaleType(ScaleType.FIT_XY);
             } else {
                 Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();
             }
        }
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
查看更多
对你真心纯属浪费
4楼-- · 2019-01-16 12:14

On the camera button click event you can try this:

final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT,
                Uri.fromFile(getTempFile(this)));
        startActivityForResult(intent, TAKE_PHOTO_CODE);

        declare TAKE_PHOTO_CODE globally as:
        private static final int TAKE_PHOTO_CODE = 1;

Add getTempFile Function in the code which will help to save the image named myImage.png you clicked in the sdcard under the folder named as your app's package name.

private File getTempFile(Context context) {
        final File path = new File(Environment.getExternalStorageDirectory(),
                context.getPackageName());
        if (!path.exists()) {
            path.mkdir();
        }
        return new File(path, "myImage.png");
    }

Now on OnActivityResult function add this:

if (requestCode == TAKE_PHOTO_CODE) {
                final File file = getTempFile(this);
                try {
                    Uri uri = Uri.fromFile(file);
                    Bitmap captureBmp = Media.getBitmap(getContentResolver(),
                            uri);
                    image.setImageBitmap(captureBmp);
                    } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

in case you get Memory issues than add below code:

@Override
    protected void onPause() {
        image.setImageURI(null);
        super.onPause();
    }

I hope this will help you

查看更多
贼婆χ
5楼-- · 2019-01-16 12:21

First lets make it clear - we have two options to take image data in onActivityResult from Camera:

1. Start Camera by passing the exact location Uri of image where you want to save.

2. Just Start Camera don't pass any Loaction Uri.


1 . IN FIRST CASE :

Start Camera by passing image Uri where you want to save:

String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/picture.jpg";  
File imageFile = new File(imageFilePath); 
Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri

Intent it = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
it.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri); 
startActivityForResult(it, CAMERA_RESULT);

In onActivityResult receive the image as:

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    if (RESULT_OK == resultCode) { 
        iv = (ImageView) findViewById(R.id.ReturnedImageView); 

        // Decode it for real 
        BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
        bmpFactoryOptions.inJustDecodeBounds = false; 

        //imageFilePath image path which you pass with intent 
        Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions); 

        // Display it 
        iv.setImageBitmap(bmp); 
    }    
} 

2 . IN SECOND CASE:

Start Camera without passing image Uri, if you want to receive image in Intent(data) :

Intent it = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
startActivityForResult(it, CAMERA_RESULT); 

In onActivityResult recive image as:

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    if (RESULT_OK == resultCode) { 
        // Get Extra from the intent 
        Bundle extras = data.getExtras(); 
        // Get the returned image from extra 
        Bitmap bmp = (Bitmap) extras.get("data"); 

        iv = (ImageView) findViewById(R.id.ReturnedImageView); 
        iv.setImageBitmap(bmp); 
    } 
} 


*****Happy Coding!!!!*****

查看更多
趁早两清
6楼-- · 2019-01-16 12:27

I suspect 3 posible problems may have created your issue:

  1. Some devices return null when you call extras.get("data"); in onActivityResult method so your problem may be a NullPointerException. To solve this, you need to pass the exact URI location to tell the camera app where you want it to store and use it in onActivityResult to retrieve the image as a Bitmap.

  2. Some other devices return a full size Bitmap when extras.get("data"); in onActivityResult. If the bitmap is too large that can result in an OutOfMemmoryError, so maybe you need to decode your image in a smaller size to not take so much memmory heap. This two links can help you in this situation:

    http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

    BitmapFactory OOM driving me nuts

  3. Maybe your activity is destroyed by the GC so you have to use onSavedInstanceState and onRestoreInstanceState to save your Activity's data. See the answer of this previous post for more information.

I don't know if you already have dealt with these issues.

Hope that helps:)

查看更多
The star\"
7楼-- · 2019-01-16 12:29

Hello all i know answer has been given but as this is also one of the easiest solution solution i have ever found

Here is the example which is it self bothering about the device!

AndroidCameraUtils - Download the project and from library project by including it below is the code snippet you can use !

private void setupCameraIntentHelper() { mCameraIntentHelper = new CameraIntentHelper(this, new CameraIntentHelperCallback() { @Override public void onPhotoUriFound(Date dateCameraIntentStarted, Uri photoUri, int rotateXDegrees) { messageView.setText(getString(R.string.activity_camera_intent_photo_uri_found) + photoUri.toString());

        Bitmap photo = BitmapHelper.readBitmap(CameraIntentActivity.this, photoUri);
        if (photo != null) {
            photo = BitmapHelper.shrinkBitmap(photo, 300, rotateXDegrees);
            ImageView imageView = (ImageView) findViewById(de.ecotastic.android.camerautil.sample.R.id.activity_camera_intent_image_view);
            imageView.setImageBitmap(photo);
        }
    }

    @Override
    public void deletePhotoWithUri(Uri photoUri) {
        BitmapHelper.deleteImageWithUriIfExists(photoUri, CameraIntentActivity.this);
    }

    @Override
    public void onSdCardNotMounted() {
        Toast.makeText(getApplicationContext(), getString(R.string.error_sd_card_not_mounted), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onCanceled() {
        Toast.makeText(getApplicationContext(), getString(R.string.warning_camera_intent_canceled), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onCouldNotTakePhoto() {
        Toast.makeText(getApplicationContext(), getString(R.string.error_could_not_take_photo), Toast.LENGTH_LONG).show();
    }

    @Override
    public void onPhotoUriNotFound() {
        messageView.setText(getString(R.string.activity_camera_intent_photo_uri_not_found));
    }

    @Override
    public void logException(Exception e) {
        Toast.makeText(getApplicationContext(), getString(R.string.error_sth_went_wrong), Toast.LENGTH_LONG).show();
        Log.d(getClass().getName(), e.getMessage());
    }
});

}

@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    mCameraIntentHelper.onSaveInstanceState(savedInstanceState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    mCameraIntentHelper.onRestoreInstanceState(savedInstanceState);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    mCameraIntentHelper.onActivityResult(requestCode, resultCode, intent);
}
}

NOTE:- I tried many examples for camera utils and ofcourse there are another ways to handle it but for beginners and person who are not too much familier with the core concepts would be more comfort with this project. THanks!

查看更多
登录 后发表回答