Android studio Android studio通过活动结果加载位图

Android studio Android studio通过活动结果加载位图,android-studio,bitmap,onactivityresult,Android Studio,Bitmap,Onactivityresult,在我的android studio项目中,我试图通过startActivityForResult从外部存储器中选择一个图像,并将所选图像加载到内存中。我还有一个bitmapploaderhelper类。下面是我调用活动以获得结果的代码片段 private void pickFromGallery() { //Create an Intent with action as ACTION_PICK Intent intent = new Intent(Intent.ACTION_GE

在我的android studio项目中,我试图通过
startActivityForResult
从外部存储器中选择一个图像,并将所选图像加载到内存中。我还有一个
bitmapploader
helper类。下面是我调用活动以获得结果的代码片段

private void pickFromGallery() {
    //Create an Intent with action as ACTION_PICK
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    // Sets the type as image/*. This ensures only components of type image are selected
    intent.setType("image/*");
    //We pass an extra array with the accepted mime types. This will ensure only components with these MIME types as targeted.
    String[] mimeTypes = {"image/jpeg", "image/png"};
    intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
    // Launching the Intent
    startActivityForResult(intent, GALLERY_REQUEST_CODE); //GALLERY_REQUEST_CODE is a constant integer
}
这是活动结果回调

public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // Result code is RESULT_OK only if the user selects an Image
    if(resultCode == Activity.RESULT_OK) {
        Bitmap imageBitmap = null;
        switch(requestCode) {
            case GALLERY_REQUEST_CODE:
                //data.getData returns the content URI for the selected Image
                File file = new File(data.getData().getPath());
                try {
                    //BitmapLoader is my helper class
                    imageBitmap = BitmapLoader.decodeSampleBitmapFromFile(file, 100, 100);
                } catch (IOException e) {
                    e.printStackTrace();
                    Toast.makeText(this, "Error while reading a file!", Toast.LENGTH_SHORT).show();
                    return;
                }

                userImage.setImageBitmap(imageBitmap);
                break;
        }
    }
}
最后,这里是
BitmapLoader
helper类

public class BitmapLoader {
private BitmapLoader() {}

private static Bitmap rotateImageIfRequired(Bitmap img, File file) throws IOException {
    ExifInterface ei = new ExifInterface(file);
    int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            return rotateImage(img, 90);
        case ExifInterface.ORIENTATION_ROTATE_180:
            return rotateImage(img, 180);
        case ExifInterface.ORIENTATION_ROTATE_270:
            return rotateImage(img, 270);
        default:
            return img;
    }
}

private static Bitmap rotateImage(Bitmap img, int degree) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degree);
    Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
    img.recycle();
    return rotatedImg;
}

private 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 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) >= reqHeight
                && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize += 1;
        }
    }

    return inSampleSize;
}

public static Bitmap decodeSampleBitmapFromFile(File file, int reqWidth, int reqHeight) throws IOException {
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(file.getPath(), options);

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

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;

    Bitmap bitmap = BitmapFactory.decodeFile(file.getPath(), options);
    return rotateImageIfRequired(bitmap, file);
}
}


问题是,当我调用
imageBitmap=BitmapLoader.decodeSampleBitmapFromFile(文件,100100),它总是引发异常。我认为问题在于我根据结果返回的Uri创建了一个文件对象。谁能告诉我这个问题是从哪里来的,并帮我写正确的代码吗?

我找到了解决这个问题的正确方法。下面是注释代码,描述了解决问题的真正方法

private void pickFromGallery() {
    //  intent with ACTION_OPEN_DOCUMENT to make
    //  content providers (gallery application, downloads application and so on)
    //  to show their files
    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    //and that files must be openable
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    //setting mime type to get only image files
    intent.setType("image/*");
    //just invoking intent
    startActivityForResult(intent, GALLERY_REQUEST_CODE);
}

//getting picked image
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // Result code is RESULT_OK only if the user selects an Image
    if(resultCode == Activity.RESULT_OK) {
        Bitmap imageBitmap;
        switch(requestCode) {
            case GALLERY_REQUEST_CODE:
                if(data == null) return;
                //ParcelFileDescriptor allowing you to close it when done with it.
                ParcelFileDescriptor parcelFileDescriptor;
                try {
                    //a method to get file descriptor via Uri(data.getData() returns a Uri, "r" means for reading) 
                    parcelFileDescriptor = getContentResolver().openFileDescriptor(data.getData(), "r");
                    //getting a descriptor from ParcelFileDescriptor
                    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
                    // and sending that descriptor to BitmapLoader, which now takes only descriptor and required width and height to load bitmap
                    imageBitmap = BitmapLoader.decodeSampleBitmapFromDescriptor(fileDescriptor, 100, 100);
                    parcelFileDescriptor.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    Toast.makeText(this, "Error while reading a file!", Toast.LENGTH_SHORT).show();
                    return;
                }
                //here you can use the loaded bitmap as you like
                userImage.setImageBitmap(imageBitmap);
                break;
        }
    }
}
最后是Bitmaploader类

public class BitmapLoader {
    private BitmapLoader() {}

    //this method uses ExifInterface to figure out how to rotate the image to bring it back to normal orientation, but that's another story.
    private static Bitmap rotateImageIfRequired(Bitmap img, FileDescriptor descriptor) throws IOException {
        ExifInterface ei = new ExifInterface(descriptor);
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                return rotateImage(img, 90);
            case ExifInterface.ORIENTATION_ROTATE_180:
                return rotateImage(img, 180);
            case ExifInterface.ORIENTATION_ROTATE_270:
                return rotateImage(img, 270);
            default:
                return img;
        }
    }
    
    //just a helper for the previous method
    private static Bitmap rotateImage(Bitmap img, int degree) {
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true);
        img.recycle();
        return rotatedImg;
    }

    // calculates how many times a bitmap should be reduced
    private 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 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize += 1;
            }
        }

        return inSampleSize;
    }

    //main working method that throws an IOException because there might be problems reading the file
    public static Bitmap decodeSampleBitmapFromDescriptor(@NonNull FileDescriptor descriptor, int reqWidth, int reqHeight) throws IOException {
        // BitmapFactory.Options helps to load only the image information first.
        final BitmapFactory.Options options = new BitmapFactory.Options();
        // must set to true to load only the image information
        options.inJustDecodeBounds = true;

        /**null is just a padding*/
        //loading into options the information about image
        BitmapFactory.decodeFileDescriptor(descriptor, null, options);

        // Calculation of the dimensions of the image for loading in accordance with the required width and height
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // now setting to false to load real bitmap with required dimensions
        options.inJustDecodeBounds = false;
        //decoding an image and returning a bitmap
        Bitmap bitmap = BitmapFactory.decodeFileDescriptor(descriptor, null, options);
        return rotateImageIfRequired(bitmap, descriptor);
    }
}

以较小的大小将图像加载到内存中非常重要,因为真实图像的位图可能需要超过500MB的RAM。

引发了什么异常?@Benjamin抱歉,但我已经找到了正确的解决方案,现在我只能说这是一个IOException。但我强烈建议阅读我自己的答案,因为有很多东西都涵盖得很好。