【问题标题】:Android : How to write camera intent in android nougatAndroid : 如何在 android nougat 中编写相机意图
【发布时间】:2019-06-26 10:50:54
【问题描述】:

在我的 android 应用程序中,当单击按钮时,我必须使用相机拍摄图像。它在除 Android 7 (Nougat) 之外的所有 Android 版本中都能完美运行。当我选择相机选项时,即使授予权限,应用程序也会退出。我认为问题出在相机调用意图中。下面是我的代码。

camera = (ImageView) dialog.findViewById(R.id.camera);

camera.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        clickCamera();
        dialog.dismiss();
    }
});

private void clickCamera() { // 1 for icon and 2 for attachment
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.CAMERA }, MY_REQUEST_CODE);
    } else {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, MY_REQUEST_CODE_STORAGE);
        } else {
            currentImageUri = getImageFileUri();
            Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
            // start the image capture Intent
            startActivityForResult(intentPicture, REQUEST_CAMERA);  // 1 for REQUEST_CAMERA (icon) and 2 for REQUEST_CAMERA_ATT (attachment)
        }
    }
}

private static Uri getImageFileUri(){
    // Create a storage directory for the images
    // To be safe(r), you should check that the SD card is mounted
    // using Environment.getExternalStorageState() before doing this

    imagePath = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyProject");
    if (!imagePath.exists()) {
        if (!imagePath.mkdirs()) {
            return null;
        } else {
            // create new folder
        }
    }

    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File image = new File(imagePath, "MyProject_" + timeStamp + ".jpg");

    if (!image.exists()) {
        try {
            image.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // Create an File Uri
    return Uri.fromFile(image);
}


@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_REQUEST_CODE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted, yay! Do the
                // contacts-related task you need to do.
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, MY_REQUEST_CODE_STORAGE);
                } else {
                    currentImageUri = getImageFileUri();
                    Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                    // start the image capture Intent
                    startActivityForResult(intentPicture, REQUEST_CAMERA);
                }
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(this, "Doesn't have permission... ", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        case MY_REQUEST_CODE_STORAGE: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                currentImageUri = getImageFileUri();
                Intent intentPicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                intentPicture.putExtra(MediaStore.EXTRA_OUTPUT, currentImageUri); // set the image file name
                // start the image capture Intent
                startActivityForResult(intentPicture, REQUEST_CAMERA);
            } else {
                // permission denied, boo! Disable the
                // functionality that depends on this permission.
                Toast.makeText(this, "Doesn't have permission...", Toast.LENGTH_SHORT).show();
            }
            return;
        }
    }
}

牛轧糖的问题是什么?是不是因为getImageFileUri()返回的Uri

【问题讨论】:

标签: android android-intent camera android-7.0-nougat


【解决方案1】:

您好,请关注this thread 作为参考。当您将 targetSDK 设置为 24 并更改以下内容时,它将向您展示如何使用 File Provider。在你的private static Uri getImageFileUri() 方法中

改变这一行

return Uri.fromFile(image);

FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", createImageFile());

希望这将帮助您解决问题。
更多信息请访问 - Setting Up File Sharing - Offical documentation

【讨论】:

  • 确实如此!适用于所有安卓版本。
  • 这里的 createImageFile() 是什么?
  • createImageFile() 是您要在 SDCard 上创建的 FILE,在您的情况下,您应该传递 File image
  • 当我尝试您的解决方案时出现此错误 java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm .PackageManager, java.lang.String)' 在空对象引用上
  • @我是否需要像在您的文档链接中那样在 AndroidManifest 中定义 FileProvider??
【解决方案2】:

尝试一下,一旦您拍照并保存到 sd 卡并取回 uri 在 Nougat 中是不同的......

在您的应用程序上实现 FileProvider 非常容易。首先,您需要在 AndroidManifest.xml 中添加一个 FileProvider 标签,如下所示:AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    <application
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>
    </application>
</manifest>

然后在res文件夹下的xml文件夹中创建provider_paths.xml文件。如果文件夹不存在,可能需要创建它。

res/xml/provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

完成! FileProvider 现在已声明并可以使用了。

最后一步是在 MainActivity.java 中更改下面的代码行

Uri photoURI = Uri.fromFile(createImageFile());

Uri photoURI = FileProvider.getUriForFile(MainActivity.this,
            BuildConfig.APPLICATION_ID + ".provider",
            createImageFile());

然后....完成了!您的应用程序现在应该可以在包括 Android Nougat 在内的任何 Android 版本上完美运行。干杯!

【讨论】:

  • @G T 外部路径名称“external_files”是否适用于每个设备?还有对带有相机意图的行 intentPicture.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 有任何要求
  • @KJEjava48 到目前为止,我仍在使用相同的 external_files,而且我也没有提到任何其他内容以及意图
  • 还有问题吗?
  • 你的解决方案正在运行
  • 我已经对你的答案投了赞成票。android_griezmann 也给出了相同的答案 b4 u,这就是为什么我将他的答案标记为正确。感谢你用完整的代码做出的回答。
【解决方案3】:

Android 的工作就是让开发者的每次更新都活得像地狱一样 :)

google 员工,这里是为(喜欢这个问题)使用过 Android 文档中的示例的开发人员提供的分步指南;

1-在你用过的部分

Uri.fromFile(image)

你需要使用这个sn-p:

Uri photoURI = FileProvider.getUriForFile(mContext,
                        "com.sample.test.fileprovider",
                        image);

当然不用说你要把com.sample.test改成你的包名。

2- 现在你需要在你的 AndroidManifest.xml 中声明你的提供者,在 Application 标签下,粘贴这个标签:

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

3-注意android:resource="@xml/file_paths"你需要在你的res/xml/文件夹下创建一个同名的xml文件file_paths并把它放进去:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="pictures"/>
</paths>

在网络上的其他几个 sn-ps 和文档本身上,它说你需要写这个

<external-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />

实际上取决于您的代码,而不是我们的代码,如果您使用 Environment.getExternalStorageDirectory().getPath() 创建文件,则不需要它,但如果您完全按照文档进行操作,则需要遵守文档

【讨论】:

    【解决方案4】:

    这里在 7.0 版本中修复了您的相机意图问题,

    file:// 不再允许(Android N)与 Intent 附加,否则它将 throw FileUriExposedException 这可能会导致您的应用程序崩溃立即调用。

    请查看问题和解决方案的全部细节。

    Soltution

    【讨论】:

    • 在您的解决方案中,能否请您定义“createImageFile()”方法
    • createImageFile() 表示,最后捕获的图​​像转换为 file.like File file = new File("Captured image uri")
    【解决方案5】:

    使用文件提供程序它会帮助你

    【讨论】:

    • 这必须是评论。坚持下去,直到您获得足够的声誉来发表评论。
    • 没有。这可以作为答案。当然,当由于某些愚蠢的原因无法发布 cmets 时,我们会发布答案。
    猜你喜欢
    • 2023-04-11
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-19
    • 2021-01-31
    相关资源
    最近更新 更多