简体   繁体   English

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

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

I am developing an app with functionality of taking image from camera or gallery.我正在开发一个具有从相机或画廊拍摄图像的功能的应用程序。 This is working fine in all the devices but not in OnePlus.这在所有设备中都可以正常工作,但在 OnePlus 中却不行。

This is the code:这是代码:

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

Code in Utils:实用程序中的代码:

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

Now the app is working fine in other devices.现在该应用程序在其他设备上运行良好。 But in OnePlus when the camera opens and we click the image and the preview is shown, at that time in the logcat we see that the app is shown dead and its restarted and it opens on app home scree.但是在 OnePlus 中,当相机打开并单击图像并显示预览时,当时在 logcat 中,我们看到应用程序显示为死机并重新启动,并在应用程序主屏幕上打开。 when we go to the particular tab from where we open the camera app, we can see the state is saved and we land on the same page.当我们从 go 到打开相机应用程序的特定选项卡时,我们可以看到 state 已保存,我们登陆同一页面。 How can we solve the issue?我们如何解决这个问题?

You probably did not give permission for your URI您可能没有为您的 URI 授予权限

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

Edit fragment most important for you is https://developer.android.com/reference/android/support/v4/content/FileProvider#Permissions对您来说最重要的编辑片段是https://developer.android.com/reference/android/support/v4/content/FileProvider#Permissions

somewhere before startActivityForResult you need to add startActivityForResult 之前的某个地方,您需要添加

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

that is pseudo code so please, check it on your side那是伪代码,所以请在你这边检查一下

EDIT 2: I've made a mistake with suggesting that you need to add that permission to your own package.编辑 2:我错误地建议您需要将该权限添加到您自己的 package 中。 You need to add it to app that will make that picture for you您需要将其添加到将为您制作该图片的应用程序

heres kotlin code for catching all apps that can do it继承人 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) }

Also for image capturing you can use simpler Intent同样对于图像捕获,您可以使用更简单的 Intent

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

cheers干杯

I tested your code on OP7Pro.我在 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.我已将结果设置为 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: @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.它会在对activity.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)的调用完成后立即返回路径,其中图像文件在返回值时可能尚未创建。 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.为确保您已捕获图像,您应该依赖 onActivityResult 并从意图中获取数据。 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.至于为什么您的应用程序崩溃,可能您正在尝试对从dispatchTakePictureIntent返回的文件执行某些操作,而当您尝试处理它时,图像实际上并没有在那个时候创建。 Hence, Unable to open content: file:///storage/emulated/0/Android/data/...因此, 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普里亚布拉塔

Just add below property in the activity tag of the Manifest file.只需在清单文件的活动标签中添加以下属性。

android:requestLegacyExternalStorage="true"

App pointing to Android 10, above flag is false by default.指向 Android 10 的应用程序,上述标志默认为false We have to set it to true .我们必须将其设置为true

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

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