繁体   English   中英

从 Oneplus 中的相机拍照时应用程序在后台崩溃

[英]App crashing in background when taking photo from camera in Oneplus

我正在开发一个具有从相机或画廊拍摄图像的功能的应用程序。 这在所有设备中都可以正常工作,但在 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 中,我们看到应用程序显示为死机并重新启动,并在应用程序主屏幕上打开。 当我们从 go 到打开相机应用程序的特定选项卡时,我们可以看到 state 已保存,我们登陆同一页面。 我们如何解决这个问题?

您可能没有为您的 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:我错误地建议您需要将该权限添加到您自己的 package 中。 您需要将其添加到将为您制作该图片的应用程序

继承人 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)

干杯

我在 OP7Pro 上测试了你的代码。

这是我用于测试的代码:

@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
}

然后,将其称为:

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

我已将结果设置为 imageview。

文件提供者:

<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>

以下是我的观察:

return tempPhotoFile 

不等待相机拍照并返回结果。 它会在对activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)的调用完成后立即返回路径,其中图像文件在返回值时可能尚未创建。 结果,行为是不可预测的。

为确保您已捕获图像,您应该依赖 onActivityResult 并从意图中获取数据。 我在其他手机中也发现了与您的代码相同的行为。 我希望我已经清楚地解释了这个问题。

至于为什么您的应用程序崩溃,可能您正在尝试对从dispatchTakePictureIntent返回的文件执行某些操作,而当您尝试处理它时,图像实际上并没有在那个时候创建。 因此, Unable to open content: file:///storage/emulated/0/Android/data/...

这是假设,您尝试像我一样将文件用作图像。

是您可能想要查看的示例实现。

希望这可以帮助。

问候

普里亚布拉塔

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

android:requestLegacyExternalStorage="true"

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM