为什么在新的 activity 中启动相机 Intent 时我的应用程序一直崩溃?

Why does my app keep crashing when launching the camera intent in a new activity?

我正在尝试在新 activity 中启动相机,但每当我按下按钮打开相机时,我的应用程序总是崩溃。如果我创建一个单独的应用程序来启动相机并拍照,它就可以正常工作。我对自己做错了什么一无所知。任何建议表示赞赏。

Activity 用于启动相机并拍照。

package com.gadget.gadgetboxv3

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import android.widget.Toast

private const val REQUEST_CODE = 42
class CaptureImage : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_capture_image)

        val button = findViewById<Button>(R.id.btnTakePicture)
        button.setOnClickListener()
        {
            val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

            if(takePictureIntent.resolveActivity(this.packageManager)!=null)
            {
                startActivity(takePictureIntent)
            }
            else
            {
                Toast.makeText(applicationContext, "Unable To Open Camera", Toast.LENGTH_SHORT).show()
            }
        }

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
    {
        val view = findViewById<ImageView>(R.id.imageView)
        if(requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK)
        {
            val takenImage = data?.extras?.get("data") as Bitmap
            view.setImageBitmap(takenImage)
        }
        else
        {
            super.onActivityResult(requestCode, resultCode, data)
        }
    }
}

CaptureImage 的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnTakePicture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="16dp"
        android:text="Take Picture"

        />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="600dp"
        android:layout_marginTop="16dp"
        android:src="@mipmap/ic_launcher"
        />


</LinearLayout>

整个应用程序的清单

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

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />

    <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/Theme.GadgetBoxV3">
        <activity
            android:name=".CaptureImage"
            android:exported="false"
            android:label="CaptureImage"
            android:parentActivityName=".MainActivity"
            android:theme="@style/Theme.GadgetBoxV3" />
        <activity
            android:name=".DisplayImage"
            android:exported="false"
            android:label="@string/title_activity_display_image"
            android:parentActivityName=".MainActivity"
            android:theme="@style/Theme.GadgetBoxV3" />
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

我用来打开 CaptureImage 的函数 activity

        //Function call to navigate to the capture image screen activity
        capture_image.setOnClickListener {
            //Creating an intent to navigate to the other screen
            val intent: Intent = Intent(this, CaptureImage::class.java)
            //Navigating to the other screen on function call
            startActivity(intent)
        }

Logcat

2022-03-21 03:22:20.577 742-742/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2022-03-21 03:22:20.578 742-742/? E/Zygote: accessInfo : 1
2022-03-21 03:22:20.618 742-742/? E/get.gadgetboxv: Unknown bits set in runtime_flags: 0x8000
2022-03-21 03:22:21.182 742-742/com.gadget.gadgetboxv3 E/OpenCV/StaticHelper: OpenCV error: Cannot load info library for OpenCV
2022-03-21 03:22:21.202 742-742/com.gadget.gadgetboxv3 E/OpenCV/StaticHelper: OpenCV error: Cannot load info library for OpenCV
2022-03-21 03:22:40.800 742-742/com.gadget.gadgetboxv3 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.gadget.gadgetboxv3, PID: 742
    java.lang.SecurityException: Permission Denial: starting Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.sec.android.app.camera/.Camera } from ProcessRecord{974fb19 742:com.gadget.gadgetboxv3/u0a269} (pid=742, uid=10269) with revoked permission android.permission.CAMERA
        at android.os.Parcel.createException(Parcel.java:2088)
        at android.os.Parcel.readException(Parcel.java:2056)
        at android.os.Parcel.readException(Parcel.java:2004)
        at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:4454)
        at android.app.Instrumentation.execStartActivity(Instrumentation.java:1716)
        at android.app.Activity.startActivityForResult(Activity.java:5258)
        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:597)
        at android.app.Activity.startActivityForResult(Activity.java:5203)
        at androidx.activity.ComponentActivity.startActivityForResult(ComponentActivity.java:583)
        at android.app.Activity.startActivity(Activity.java:5587)
        at android.app.Activity.startActivity(Activity.java:5555)
        at com.gadget.gadgetboxv3.CaptureImage.onCreate$lambda-0(CaptureImage.kt:26)
        at com.gadget.gadgetboxv3.CaptureImage.$r8$lambda$A3JJRk2duhFHwC-ZfpOzOx8lFhs(Unknown Source:0)
        at com.gadget.gadgetboxv3.CaptureImage$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
        at android.view.View.performClick(View.java:7862)
        at android.widget.TextView.performClick(TextView.java:15004)
        at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1199)
        at android.view.View.performClickInternal(View.java:7831)
        at android.view.View.access00(View.java:879)
        at android.view.View$PerformClick.run(View.java:29359)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:8167)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
     Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.wm.ActivityStackSupervisor.checkStartAnyActivityPermission(ActivityStackSupervisor.java:1447)
        at com.android.server.wm.ActivityStarter.startActivity(ActivityStarter.java:980)
        at com.android.server.wm.ActivityStarter.startActivity(ActivityStarter.java:732)
        at com.android.server.wm.ActivityStarter.startActivityMayWait(ActivityStarter.java:2074)
        at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:646)

您正在发生 java.lang.SecurityException: Permission Denial ... with revoked permission android.permission.CAMERA - 您的应用没有相机访问权限

使用

问题:在您的代码中您没有检查访问相机意图的权限这就是您的应用程序崩溃的原因。

回答: 尝试添加以下代码:

private static final int MY_CAMERA_REQUEST_CODE = 100;

@RequiresApi(api = Build.VERSION_CODES.M)

if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.CAMERA}, MY_CAMERA_REQUEST_CODE);
}

onCreate 函数和以下代码:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == MY_CAMERA_REQUEST_CODE) {
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        Toast.makeText(this, "camera permission granted", Toast.LENGTH_LONG).show();
    } else {
        Toast.makeText(this, "camera permission denied", Toast.LENGTH_LONG).show();
    }
}

}

相机权限属于危险权限类别,因此从 M 开始,在运行时必须请求权限。请检查以下代码以供参考。

ActivityCompat.requestPermissions( activity, arrayOf(Manifest.permission.CAMERA), YOUR_REQUEST_CODE )

需要在打开相机之前调用。执行此代码后,将显示 grant/deny 包管理器权限的对话框。

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { when (requestCode) { YOUR_REQUEST_CODE -> {} }

确保您已在清单中添加权限

<uses-permission android:name="android.permission.CAMERA" />

你也可以使用外部库来显示权限对话框,如Dexter、PermissionsDispatcher或KPermissions,这会让你更简洁..