【问题标题】:Camera.open works on Android 4.2.2, but fails on 6.0.1Camera.open 适用于 Android 4.2.2,但在 6.0.1 上失败
【发布时间】:2016-09-15 09:49:33
【问题描述】:

我有 2 台设备来测试我的应用:运行 Android 4.2.2 的 Acer v370 和运行 6.0.1 的三星 Galaxy S6

该应用在 Acer 上运行良好,但在 S6 上立即崩溃。我正在使用 _camera = Camera.open(0); 并且调试说它此时崩溃了。

我得到的错误是:

09-15 11:24:33.491 15284-15284/com.user.qrReader E/AndroidRuntime: FATAL EXCEPTION: main
  Process: com.user.qrReader, PID: 15284
  java.lang.RuntimeException: Unable to resume activity {com.user.qrReader/com.user.qrReader.MainActivity}:
  java.lang.RuntimeException: Fail to connect to camera service
      at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4156)
      at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250)
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3361)
      at android.app.ActivityThread.access$1100(ActivityThread.java:222)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
      at android.os.Handler.dispatchMessage(Handler.java:102)
      at android.os.Looper.loop(Looper.java:158)
      at android.app.ActivityThread.main(ActivityThread.java:7229)
      at java.lang.reflect.Method.invoke(Native Method)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
  Caused by: java.lang.RuntimeException: Fail to connect to camera service
      at android.hardware.Camera.<init>(Camera.java:568)
      at android.hardware.Camera.open(Camera.java:405)
      at com.user.qrReader.CameraPreview.openCamera(CameraPreview.java:206)
      at com.user.qrReader.CameraPreview.captureStart(CameraPreview.java:288)
      at com.user.qrReader.QRReaderAppManager.onResume(QRReaderAppManager.java:208)
      at com.user.qrReader.MainActivity.onResume(MainActivity.java:187)
      at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1286)
      at android.app.Activity.performResume(Activity.java:6987)
      at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4145)
      at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250) 
      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3361) 
      at android.app.ActivityThread.access$1100(ActivityThread.java:222) 
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) 
      at android.os.Handler.dispatchMessage(Handler.java:102) 
      at android.os.Looper.loop(Looper.java:158) 
      at android.app.ActivityThread.main(ActivityThread.java:7229) 
      at java.lang.reflect.Method.invoke(Native Method) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

这是我的清单中的权限:

<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />

我不能使用 camera2,因为我必须让应用至少兼容 android 4,而且我不知道该往哪个方向发展。它一定与新的 android 相关,但我找不到。有什么想法吗?

编辑:您也可以手动执行此操作,安装 apk 后,转到设置>应用程序>应用程序管理器>{我的应用程序}>权限>允许相机。当然,如果您有解决方案,那将是可怕且无用的,但是在我调试时它对我有所帮助,因此我将把它留在这里。 谢谢你的回答。

【问题讨论】:

  • 可能是由于棉花糖中的运行时权限
  • 在 6.0 上你需要在运行时检查权限,而 CAMERA 是硬权限所以你需要检查它
  • 也许this 可以提供一些帮助。
  • 您需要检查权限的示例并保存吗?
  • @Rodriquez 是的,谢谢,那太好了。

标签: java android android-camera android-4.2-jelly-bean android-6.0.1-marshmallow


【解决方案1】:

为了检查权限,我创建了一个单独的类,如下所示:

  public class MarshMallowPermission {

    public static final int RECORD_PERMISSION_REQUEST_CODE = 1;
    public static final int EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE = 2;
    public static final int CAMERA_PERMISSION_REQUEST_CODE = 3;
    Activity activity;

    public MarshMallowPermission(Activity activity) {
        this.activity = activity;
    }

    public boolean checkPermissionForRecord(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO);
        if (result == PackageManager.PERMISSION_GRANTED){
            return true;
        } else {
            return false;
        }
    }

    public boolean checkPermissionForExternalStorage(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        if (result == PackageManager.PERMISSION_GRANTED){
            return true;
        } else {
            return false;
        }
    }

    public boolean checkPermissionForCamera(){
        int result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
        if (result == PackageManager.PERMISSION_GRANTED){
            return true;
        } else {
            return false;
        }
    }

    public void requestPermissionForRecord(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.RECORD_AUDIO)){
           Toast.makeText(activity, "Microphone permission needed for recording. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.RECORD_AUDIO},RECORD_PERMISSION_REQUEST_CODE);
        }
    }

    public void requestPermissionForExternalStorage(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)){
            Toast.makeText(activity, "External Storage permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
        }
    }

    public void requestPermissionForCamera(){
        if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)){
            Toast.makeText(activity, "Camera permission needed. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
        } else {
            ActivityCompat.requestPermissions(activity,new String[]{Manifest.permission.CAMERA},CAMERA_PERMISSION_REQUEST_CODE);
        }
    }
}

那么,为了得到

MarshMallowPermission marshMallowPermission = new MarshMallowPermission(this);


public void getPhotoFromCamera() {

    if (!marshMallowPermission.checkPermissionForCamera()) {
        marshMallowPermission.requestPermissionForCamera();
    } else {
        if (!marshMallowPermission.checkPermissionForExternalStorage()) {
            marshMallowPermission.requestPermissionForExternalStorage();
        } else {
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File mediaStorageDir = new File(
                    Environment.getExternalStorageDirectory()
                            + File.separator
                            + getString(R.string.directory_name_corp_chat)
                            + File.separator
                            + getString(R.string.directory_name_images)
            );

            if (!mediaStorageDir.exists()) {
                mediaStorageDir.mkdirs();
            }

            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
                    Locale.getDefault()).format(new Date());
            try {
                mediaFile = File.createTempFile(
                        "IMG_" + timeStamp,  /* prefix */
                        ".jpg",         /* suffix */
                        mediaStorageDir      /* directory */
                );
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mediaFile));
                startActivityForResult(takePictureIntent, PICK_FROM_CAMERA);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

【讨论】:

  • 实际上,当我只使用一个权限时它可以工作(我使用实时二维码扫描,所以我不需要记录或外部存储)但现在它不起作用:如果我要求 2 个权限,我获取 W/Activity: Can reqeust only a set of permissions,有错字!我没有在你的代码中找到它,所以我不知道它来自哪里。无论如何,我不能连续要求 2 个权限:(
  • 已解决,我在this link 之后提出了一个新请求,其中包含我的所有权限。然后另一个请求就过时了。
【解决方案2】:

"注意:如果您的应用程序以 M 及以上为目标并声明使用未授予的 CAMERA 权限,则尝试使用此操作将导致 SecurityException。"

这真的很奇怪。完全没有意义。该应用程序使用带有操作 IMAGE_CAPTURE 的 Intent 声明相机权限,只是遇到了 SecurityException。但是,如果您的应用未使用带有动作 IMAGE_CAPTURE 的意图声明相机权限,则可以毫无问题地启动相机应用。

解决方法是检查应用是否在清单中包含相机权限,如果是,请在启动意图之前请求相机权限。

这是检查权限是否包含在清单中的方法,无论是否授予权限。

public boolean hasPermissionInManifest(Context context, String permissionName) {
final String packageName = context.getPackageName();
try {
    final PackageInfo packageInfo = context.getPackageManager()
            .getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
    final String[] declaredPermisisons = packageInfo.requestedPermissions;
    if (declaredPermisisons != null && declaredPermisisons.length > 0) {
        for (String p : declaredPermisisons) {
            if (p.equals(permissionName)) {
                return true;
            }
        }
    }
} catch (NameNotFoundException e) {

}
return false;

}

【讨论】:

  • 谢谢,我会试试的。我假设我做了“if (hasPermissionInManifest(...)) camera.open(0);” ?
【解决方案3】:

自 API 21 起,Camera 类已被弃用。

Camera class documentation

建议使用新的 android.hardware.camera2 API 应用程序。

遗憾的是我还没有体验过,所以我无法提供更多帮助。

还有一个小机会,试试吧:

    Camera.open(); // Without argument

问候

【讨论】:

  • 我编辑了帖子,我不能使用 camera2,因为它是在 API 级别 21 中引入的。我尝试了没有任何参数但没有成功。
【解决方案4】:

这是在活动中。我检查权限并保存它,将我的一些权限更改为有关 CAMERA 的权限。这是工作示例。

private static final int REQUEST_CODE_GET_ACCOUNTS = 101;
    private static final int REQUEST_AUDIO_PERMISSION = 102;

 @TargetApi(23)
public void checkAudioPermission() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        playerFragment.setupVisualizerFxAndUI();
        return;
    }
    if (this.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager
            .PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
                REQUEST_AUDIO_PERMISSION);
    } else {
        playerFragment.setupVisualizerFxAndUI();
    }
}

@TargetApi(23)
public void checkGmailPermission() {
    if (isDeviceOnline()) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            showGmailRecFragment(true);
            return;
        }
        if (this.checkSelfPermission(Manifest.permission.GET_ACCOUNTS) != PackageManager
                .PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.GET_ACCOUNTS},
                    REQUEST_CODE_GET_ACCOUNTS);
            return;
        } else {
            showGmailRecFragment(true);
        }
    } else {
        Utils.showToast(this, getString(R.string.no_internet));
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[]
        grantResults) {
    switch (requestCode) {
        case REQUEST_CODE_GET_ACCOUNTS:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                showGmailRecFragment(true);
            } else {
                Utils.showToast(this, getString(R.string.accounts_permision_denied));
            }
            break;
        case REQUEST_AUDIO_PERMISSION:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                playerFragment.setupVisualizerFxAndUI();
            } else {
                Utils.showToast(this, getString(R.string.audio_permission_denied));
            }
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            break;
    }
}

当我想再次检查权限或用户拒绝它时,这是在片段上。这也保存了权限

private void setupViewVisualizer() {
    if (!isLiveTv && !homeVideo.isVideoType()) {
        ((PlayerActivity) activity).checkAudioPermission();
    } else {
        return;
    }
}

【讨论】:

  • 我不确定这就是我要找的东西。我之所以这么说,是因为我有一个类似的项目,使用相同的 API 级别和相同的 camera.open() 工作正常。奇怪的是,其中一个所有“相机”事件都被交叉,而不是另一个,我不知道为什么。我敢肯定,如果我发现相机可以工作的不同之处。我做了一些截图:i.imgur.com/LS5Y4v9.png 如您所见,代码是相同的,但相机在第二个项目中被交叉。 i.imgur.com/jfWCE50.png 这是清单,因为我怀疑它与 API 级别和版本有关。
  • 这两个项目非常相似并且是从同一个基础构建的,但是一个崩溃而不是另一个。我没有发现“为什么相机越过”,就像“如何让 Android Studio '接受它'”一样,所有的解决方案都非常复杂并且避免了问题的根源(老实说,我可能错了)
  • 原来一个有"@SuppressWarnings("deprecation")" 而另一个没有。它没有解决为什么一个工作而不是另一个工作的问题,但就是这样
猜你喜欢
  • 2017-10-17
  • 1970-01-01
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 2021-09-27
  • 1970-01-01
相关资源
最近更新 更多