在某些设备上,ImageView setImageBitmap无法正常工作

8

我在练习使用相机API,具体操作如下:

a. 为拍摄的图片设置了一个目录(用于startActivityForResult)。

b. 设置了位图,以便保存在应用程序中后能够显示该图片。

以下是相关代码:

设置目录。

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;
}

应用程序中的全局变量

// 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;

相机实现逻辑
// 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();
    }
}

我遇到的问题是,对于我测试过的某些设备,应用程序显示拍摄的图像预览为空白,而在其他设备中,应用程序完全正常工作。
为什么会出现空白反馈?在某些情况下,当保存图像时,用户没有被引导到我的应用程序,而是卡在相机应用程序中。
请帮忙解决。
6个回答

3

我曾经遇到相同的问题,通过将视图渲染方式更改为软件实现解决了它。

ImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);


它可以工作,但我不明白为什么我的图像会旋转90度显示... - Sirop4ik
你需要读取相机的方向来解决这个问题。 - Majid M. Alzariey

2

至少对于Galaxy S4上的Kitkat 4.4.2版本,使用相对布局时,我必须在刚刚调用setImageBitmap()方法的ImageView上调用invalidate()方法。如果我不这样做,我就会得到空白屏幕。在在setImageBitmap()方法后添加invalidate()方法之后,我才得到了图像。


1

高效加载位图的尝试:

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;}

1
实际上这是一个设置,但由于某些原因它没有出现。
profileImageView.post(new Runnable() {
                    @Override
                    public void run() {
                        profileImageView.setImageBitmap(bm);
                    }
                });

这对我有效。


0
在我的情况下,通过在XML中添加android:layerType="software"来解决问题。
<ImageView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layerType="software"
    android:src="@drawable/placeholder"/>

希望这对你也有所帮助!


0
我解决这个问题的方法之一是在设置FileUri时,使用SharedPreferences存储Uri。因此,在我的代码中:
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);
}

在我的onActivityResult回调函数中:
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);
    }
}

额外奖励 :)

在我的previewImage方法中,我已经对方向进行了调整,代码如下:

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;
}

在这个方法中,我调用另一个名为adjustOrientation的方法,它为我提供了用于修复图像的Matrix
// 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;
}

这是我对这个问题的实现,如果有人有更好的实现,请发表 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接