2

我正在开发一个具有从相机或画廊拍摄图像的功能的应用程序。这在所有设备中都可以正常工作,但在 OnePlus 中却不行。

这是代码:

public File dispatchTakePictureIntent(Activity activity) {
        File tempPhotoFile = null;
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {

            try {
                tempPhotoFile = Utils.createImageFile(activity);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (tempPhotoFile != null) {
                Uri photoURI = FileProvider.getUriForFile(activity, Utils.getFileProvider(activity), tempPhotoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                takePictureIntent.setClipData(ClipData.newRawUri("", photoURI));
                takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                activity.startActivityForResult(takePictureIntent, Constants.REQUEST_IMAGE_CAPTURE);
            }
        }
        return tempPhotoFile;
    }

实用程序中的代码:

public static File createImageFile(Context context) throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );

        // Save a file: path for use with ACTION_VIEW intents
        return image;
    }

现在该应用程序在其他设备上运行良好。但是在 OnePlus 中,当相机打开并单击图像并显示预览时,当时在 logcat 中,我们看到应用程序显示为死机并重新启动,并在应用程序主屏幕上打开。当我们从打开相机应用程序的位置转到特定选项卡时,我们可以看到状态已保存并进入同一页面。我们如何解决这个问题?

4

3 回答 3

0

只需在清单文件的活动标签中添加以下属性。

android:requestLegacyExternalStorage="true"

指向 Android 10 的应用程序,默认情况下,上述标志为false。我们必须将其设置为true

于 2020-04-23T17:16:01.057 回答
0

您可能没有为您的 URI 授予权限

请研究 https://developer.android.com/reference/android/support/v4/content/FileProvider

对您来说最重要的编辑片段是 https://developer.android.com/reference/android/support/v4/content/FileProvider#Permissions

startActivityForResult 之前的某个地方,您需要添加

 activity.grantUriPermission(activity.getActivityInfo().getPackageName(), photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)

那是伪代码,所以请在你这边检查一下

编辑 2:我错误地建议您需要将该权限添加到您自己的包中。您需要将其添加到将为您制作该图片的应用程序

这是用于捕获所有可以执行此操作的应用程序的 kotlin 代码

val resInfoList = activity.packageManager.queryIntentActivities(Intent(MediaStore.ACTION_IMAGE_CAPTURE), PackageManager.MATCH_DEFAULT_ONLY)
    resInfoList
            .map { it.activityInfo.packageName }
            .forEach { this.grantUriPermission(it, photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION) }

同样对于图像捕获,您可以使用更简单的 Intent

    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
            startActivityForResult(takePictureIntent, PICK_CAMERA_CODE)

干杯

于 2019-11-06T13:27:40.520 回答
0

I tested your code on OP7Pro.

Here is the code I used for the test:

@Throws(IOException::class)
fun createImageFile(context: Context): File {
    // Create an image file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.ENGLISH).format(Date())
    val imageFileName = "JPEG_" + timeStamp + "_"
    val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)

    // Save a file: path for use with ACTION_VIEW intents
    return File.createTempFile(
        imageFileName, /* prefix */
        ".jpg", /* suffix */
        storageDir      /* directory */
    )
}

private fun dispatchTakePictureIntent(activity: Activity): File? {
    var tempPhotoFile: File? = null
    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    if (takePictureIntent.resolveActivity(activity.packageManager) != null) {

        try {
            tempPhotoFile = createImageFile(activity)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        if (tempPhotoFile != null) {
            val photoURI = FileProvider.getUriForFile(
                activity,
                applicationContext.packageName + ".fileprovider",
                tempPhotoFile
            )
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
            takePictureIntent.clipData = ClipData.newRawUri("", photoURI)
            takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
            activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
        }
    }
    return tempPhotoFile
}

Then, called it like:

btnOpenCamera.setOnClickListener{
     val r = dispatchTakePictureIntent(this)
     imageView.setImageDrawable(Drawable.createFromPath(r?.path))
}

I have set the result in a imageview.

File Provider:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths" />
</provider>

@xml/provider_paths:

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

Following are my observations:

return tempPhotoFile 

doesn't wait for the camera to take the picture and come back with the result. It returns the path instantly as the call to activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE) is completed, where the image file might not have been created at the time of it returning the value. As a result, the behaviour is unpredictable.

To ensure that you have captured the image, you should rely on the onActivityResult and get the data from the intent. I have found the same behaviour in other phones also with your code. I hope I have explained the problem clearly.

As to why your app is crashing, probably you are trying to do something with the file it is returning from dispatchTakePictureIntent, and when you try to process it, the image actually isn't created by that time. Hence, Unable to open content: file:///storage/emulated/0/Android/data/...

This is assuming, you tried to use the file as an Image as I did.

Here is an example implementation you might want to look at.

Hope this helps.

Regards

Priyabrata

于 2019-11-07T06:09:50.010 回答