ImageView setImageBitmap not working on certain de

2019-06-22 14:08发布

问题:

I was practicing around with the Camera API for which I did the following:

a. Setup a directory for the image captured (for startActivityForResult)

b. Setup the Bitmap so that the image could be shown once saved in the app itself.

Here's the code for the following:

Setting up the directory.

private static File getOutputMediaFile(int type) {

    // External sdcard location
    File mediaStorageDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            IMAGE_DIRECTORY_NAME);
    // Create the storage directory if it does not exist
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d(IMAGE_DIRECTORY_NAME, "Oops! Failed create "
                    + IMAGE_DIRECTORY_NAME + " directory");
            return null;
        }
    }
    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
            Locale.getDefault()).format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator
                + "IMG_" + timeStamp + ".jpg");
    } else {
        return null;
    }

    return mediaFile;
}

Global variables in the application

// Activity request codes
private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100;
public static final int MEDIA_TYPE_IMAGE = 1;

// directory name to store the captured images
private static final String IMAGE_DIRECTORY_NAME = "my_camera_app";

private Uri fileUri;

// Views
ImageView photo;
Button camera;

Camera implementation logic

// Use camera function
private void captureImage() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE);

    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

    // start the image capture Intent
    startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) {
        if (resultCode == RESULT_OK) {
            // Successfully captured the image
            // display in imageview
            previewImage();
        } else {
            // failed to capture image
            Toast.makeText(getApplicationContext(),
                    "Sorry! Failed to capture image", Toast.LENGTH_SHORT)
                    .show();
        }
    }
}

private void previewImage() {
    try {
        // Bitmap factory
        BitmapFactory.Options options = new BitmapFactory.Options();

        // Downsizing image as it throws OutOfMemory exception for larger
        // images
        options.inSampleSize = 3;

        final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(),
                options);

        photo.setImageBitmap(bitmap);

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

The problem I am having is that ... for some of the devices that I tested the app, the app shows a blank preview of the image shot while in others the app works completely well.

Why am I getting a blank feedback ? and in some of the cases, when an image is saved, the user is not directed to my app, instead the user is stuck in the camera app.

Please do help.

回答1:

At least for Kitkat 4.4.2 on a Galaxy S4, with a relative layout, I had to call invalidate() on the ImageView that i just setImageBitmap on. If i didn't, i got the blank screen. After adding the invalidate() after setImageBitmap(), then I got the image.



回答2:

I had the same problem and solved it by changing the rendering of the view to software

ImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);



回答3:

try loading bitmap efficiently:

public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    //BitmapFactory.Options optionss = new BitmapFactory.Options();
    //optionss.inPreferredConfig = Bitmap.Config.RGB_565;


    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    options.inPreferredConfig = Bitmap.Config.RGB_565;
    BitmapFactory.decodeFile(path,options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeFile(path, options);
}
public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

    final int halfHeight = height / 2;
    final int halfWidth = width / 2;

    // Calculate the largest inSampleSize value that is a power of 2 and keeps both
    // height and width larger than the requested height and width.
    while ((halfHeight / inSampleSize) > reqHeight
            && (halfWidth / inSampleSize) > reqWidth) {
        inSampleSize *= 2;
    }
}

return inSampleSize;}


回答4:

One way I got around this problem was when setting the FileUri, I stored the Uri using SharedPreferences. So in my code:

public void takePhoto() {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    fileUri = FileHelper.getOutputMediaFileUri();
    // Store uri to SharedPreferences
    pref.setImageUri(fileUri.toString());
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
    startActivityForResult(intent, TAKE_PICTURE);
}

In my onActivityResult callback:

if (requestCode == TAKE_PICTURE && resultCode == RESULT_OK) {
    // If user is taking photo then only call the SharedPreferences
    // If user is selecting photo from gallery, we can use the Intent data
    fileUri = Uri.parse(pref.getImageUri());
    if (fileUri.getPath().toString().length() < 1) {
        Toast.makeText(getApplicationContext(),
                "Sorry something went wrong ... Please try again",
                Toast.LENGTH_LONG).show();
    } else {
        String path = fileUri.getPath().toString();
        db_img_path = path;
        imageholder.setVisibility(View.VISIBLE);
        Bitmap bitmap = PathtoImage.previewImage(path);
        imagepreview.setImageBitmap(bitmap);
    }
}

Bonus :)

In my previewImage method, I have made adjustments for orientation, the code looks like this :

public static Bitmap previewImage(String path) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 4;
    final Bitmap bitmap = BitmapFactory.decodeFile(path, options);
    // Providing adjustment so that the image is shown in the correct orientation
    Matrix adjustment = adjustOrientation(path);
    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
            bitmap.getWidth(), bitmap.getHeight(), adjustment, true);
    return resizedBitmap;
}

In this method I call another method adjustOrientation which gives me the Matrix fix to the image.

// Adjustment for orientation of images
public static Matrix adjustOrientation(String path) {
    Matrix matrix = new Matrix();
    try {
        ExifInterface exifReader = new ExifInterface(path);

        int orientation = exifReader.getAttributeInt(
                ExifInterface.TAG_ORIENTATION, -1);

        if (orientation == ExifInterface.ORIENTATION_NORMAL) {
            // do nothing
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            matrix.postRotate(90);
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            matrix.postRotate(180);
        } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            matrix.postRotate(270);
        }

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

    return matrix;
}

This is my implementation for the issue, if anyone has a better implementation to this, please do post :)



回答5:

Actually it is setting but it doesnt appear for some reason.

profileImageView.post(new Runnable() {
                    @Override
                    public void run() {
                        profileImageView.setImageBitmap(bm);
                    }
                });

This works for me.