在Android Nougat上拍摄照片后,BitmapFactory无法解码Uri中的Bitmap

Sil*_*ght 12 android bitmap android-camera-intent android-fileprovider android-7.0-nougat

我试图拍照然后使用照片.这就是我做的.

我的设备是Nexus 6P(Android 7.1.1).

首先,我创建了一个Uri:

Uri mPicPath = UriUtil.fromFile(this, UriUtil.createTmpFileForPic());
//Uri mPicPath = UriUtil.fromFile(this, UriUtil.createFileForPic());
Run Code Online (Sandbox Code Playgroud)

然后,我开始Intent:

Intent intent = ActivityUtils.getTakePicIntent(mPicPath);
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivityForResult(intent, RequestCode.TAKE_PIC);
}
Run Code Online (Sandbox Code Playgroud)

最后,我处理了这个Uri问题onActivityResult:

if (requestCode == RequestCode.TAKE_PIC) {
    if (resultCode == RESULT_OK && mPicPath != null) {
        Bitmap requireBitmap = BitmapFactory.decodeFile(mPicPath.getPath());
        //path is like this: /Download/Android/data/{@applicationId}/files/Pictures/JPEG_20170216_173121268719051242.jpg
        requireBitmap.recycle();//Here NPE was thrown.
    }
}
Run Code Online (Sandbox Code Playgroud)

在此期间,以下是UriUtil:

public class UriUtil {

    public static File createFileForPic() throws IOException {
        String fileName = "JPEG_" + new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.getDefault()).format(new Date()) + ".jpg";
        File storageDic = SPApplication.getInstance().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        return new File(storageDic, fileName);
    }

    public static File createTmpFileForPic() throws IOException {
        String fileName = "JPEG_" + new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.getDefault()).format(new Date());
        File storageDic = SPApplication.getInstance().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        return File.createTempFile(fileName, ".jpg", storageDic);
    }

    public static Uri fromFile(@NonNull Context context, @NonNull File file) {
        if (context == null || file == null) {
            throw new RuntimeException("context or file can't be null");
        }
        if (ActivityUtils.requireSDKInt(Build.VERSION_CODES.N)) {
            return FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".file_provider", file);
        } else {
            return Uri.fromFile(file);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并且getTakePicIntent(Uri):

public static Intent getTakePicIntent(Uri mPicPath) {
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, mPicPath);
    if (!ActivityUtils.requireSDKInt(Build.VERSION_CODES.KITKAT_WATCH)) {//in pre-KitKat devices, manually grant uri permission.
        List<ResolveInfo> resInfoList = SPApplication.getInstance().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        for (ResolveInfo resolveInfo : resInfoList) {
            String packageName = resolveInfo.activityInfo.packageName;
            SPApplication.getInstance().grantUriPermission(packageName, mPicPath, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }
    } else {
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    }
    return intent;
}
Run Code Online (Sandbox Code Playgroud)

并且requireSDKInt:

public static boolean requireSDKInt(int sdkInt) {
    return Build.VERSION.SDK_INT >= sdkInt;
}
Run Code Online (Sandbox Code Playgroud)

除了Android Nougat(7.xx)之外,一切都在不同的Android API上运行.即使提供了'FileProvider','requireBitmap'也始终返回为'null'.

读取日志后,FileNotFoundException被抛出BitmapFactory.它就像:

BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /Download/Android/data/{@applicationId}/files/Pictures/JPEG_20170216_1744551601425984925.jpg (No such file or directory)
Run Code Online (Sandbox Code Playgroud)

似乎一切都很清楚,但我仍然无法理解.

怎么会这样?显然我创造了一个File!我怎么能解决这个问题?有任何想法吗?

Rag*_*dan 9

我试过你的代码.这是我尝试的样本.https://github.com/raghunandankavi2010/SamplesAndroid/tree/master/StackOverFlowTest.

看看这个博客https://commonsware.com/blog/2016/03/15/how-consume-content-uri.html

在博客commonsware提到你不应该做new File (mPicPath.getPath()).

相反,你应该使用下面的 onActivityResult

try {
       InputStream ims = getContentResolver().openInputStream(mPicPath);
       // just display image in imageview
       imageView.setImageBitmap(BitmapFactory.decodeStream(ims));
    } catch (FileNotFoundException e) {
            e.printStackTrace();
    }
Run Code Online (Sandbox Code Playgroud)

和xml

 <external-files-path name="external_files" path="path" />
Run Code Online (Sandbox Code Playgroud)

注意:它是您拥有的内容uri.在我的手机上,我得到如下的uri.仅在Nexus6p上测试过.

内容://com.example.raghu.stackoverflowtest.fileProvider/external_files/Pictures/JPEG_20170424_161429691143693160.jpg

更多关于文件提供者https://developer.android.com/reference/android/support/v4/content/FileProvider.html

  • 是的,最后,只有`BitmapFactory.decodeStream(inputStream)` 有效。 (2认同)