无法为相机的 PutExtra 方法获取文件 URI

Unable to get File Uri for PutExtra method for camera

我正在尝试构建一个相机 activity 来拍摄照片并将其保存到 SD 卡中。但是我发现我的代码在用于获取文件 Uri 的方法以及 putExtra() 方法处出现问题。

调用startCamera()函数时,相机意图不会启动并杀死activity。

private void startCamera(int actionCode) {
    //Create a camera intent
    Intent camera_intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    switch (actionCode) {
        case CAM_REQ_CODE:
        File photo_file = null;
        try {
            photo_file = setUpPhotoFile();
        } catch (IOException e) {
            e.printStackTrace();
            photo_file = null;
            photo_path = null;
        }
        // Continue only if the File was successfully created
        if (photo_file != null) {
            photo_path = photo_file.getAbsolutePath();
            Uri photoURI = Uri.fromFile(photo_file);  //works
            //Uri photoURI = FileProvider.getUriForFile(InStore.this,"babygroot.iamgroot.fileprovider", photo_file);
            // PROBLEM!! how to overcome putExtra method to pass photo URI to MediaStore.EXTRA_OUTPUT
            camera_intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(camera_intent, CAM_REQ_CODE);
        }
        break;
        default:
            break;
    }
}

这是我的清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="babygroot.iamgroot">

    <!-- To auto-complete the email text field in the login form with the user's emails -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.READ_PROFILE" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <uses-feature android:name="android.hardware.camera" />
    <!--<uses-feature android:name="android.hardware.camera2" /> -->
    <uses-feature android:name="android.hardware.camera.autofocus" />


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="babygroot.iamgroot.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths"></meta-data>
        </provider>

        <activity android:name=".LoginScreen">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".QRCode"
            android:parentActivityName=".LoginScreen" />
        <activity
            android:name=".SignUp"
            android:parentActivityName=".LoginScreen" />
        <activity
            android:name=".InStore"
            android:parentActivityName=".QRCode" />
        <activity android:name=".CheckOut" />
    </application>

</manifest>

InStoreactivity是使用相机功能的地方。

这是失败时的堆栈跟踪

Process: babygroot.iamgroot, PID: 26238
    java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Pictures/IAMGROOTPics/IMG_20171213_141445_787397456.jpg
                  at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:712)
                  at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:401)
                  at babygroot.iamgroot.InStore.startCamera(InStore.java:172)
                  at babygroot.iamgroot.InStore.showCameraPreview(InStore.java:111)
                  at babygroot.iamgroot.InStore.access[=12=]0(InStore.java:28)
                  at babygroot.iamgroot.InStore.onClick(InStore.java:63)
                  at android.view.View.performClick(View.java:5646)
                  at android.view.View$PerformClick.run(View.java:22459)
                  at android.os.Handler.handleCallback(Handler.java:761)
                  at android.os.Handler.dispatchMessage(Handler.java:98)
                  at android.os.Looper.loop(Looper.java:156)
                  at android.app.ActivityThread.main(ActivityThread.java:6523)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

res/xml/file_paths.xml:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/com.example.package.babygroot.iamgroot/files/Pictures" />
</paths>

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="Android/data/com.example.package.babygroot.iamgroot/files/Pictures" />
</paths>

问题是 android 现在不允许其他应用程序读取文件,这就是您的代码崩溃的原因。看到这个 7.0 behaviour changes

请参阅本教程以使用 FileProvider 完成任务 https://drivy.engineering/android-fileprovider/

您基本上声明了一个共享文件位置,以便应用程序可以在那里进行读取和写入。然后在那里创建一个文件并使用该文件的 Uri 打开相机意图。

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="shared" path="shared/"/>
</paths>

Menfiest 文件声明

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="<your provider authority>"
    android:exported="false"
    android:grantUriPermissions="true">
  <meta-data
      android:name="android.support.FILE_PROVIDER_PATHS"
      android:resource="@xml/file_provider_paths"/>
</provider>

终于

Uri sharedFileUri = FileProvider.getUriForFile(this, <your provider auhtority>, sharedFile);

以我为例

        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.TITLE, "Image File name");
        mCapturedImageURI = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI);
        startActivityForResult(intentPicture,REQUEST_IMAGE_CAPTURE);

以上代码运行良好。

尝试用这个替换您的代码。

并处理 onActivityResult 以取回 activity 中的图像。

希望这有帮助!