Android M要求onSurfaceTextureAvailable回调中的权限不在Activity中

时间:2017-08-07 12:59:02

标签: android android-camera kotlin android-6.0-marshmallow android-permissions

症状:首次启动时,我的应用程序崩溃为java.lang.SecurityException: Lacking privileges to access camera service。我得到“不幸的是你的应用程序已崩溃”对话框,单击“确定”,在此对话框下有两个对话框要求必要的权限。我对两者说“OK”,从现在起我的应用程序工作。接下来的开始没有崩溃。

原因:经过一段时间的阅读和调试后,我开始明白我的应用程序问题是它想要在获得所需权限之前做一些与相机相关的逻辑(onSurfaceTextureAvailable回调在我的CameraHandler类中)或在相机表面视图到达前景之前。

关于SO和Github上的类似错误有很多问题,但我仍然很难弄明白。

我尝试通过this回答,但我的设置有点不同,即我的Camera逻辑位于不属于Activity的不同类中,我真的想保持这种方式不要弄乱我的CameraActivity类。有没有一个很好的方法来解决这个问题?

如何确保在触发我的CameraHandler类中的onSurfaceTextureAvailable时,已授予权限,以便我在第一次运行时没有java.lang.SecurityException: Lacking privileges to access camera service

这是我在SurfaceHandler类中的SurfaceTextureListener:

    private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
    override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
        openCamera(width, height) //this line here makes my app crash
    }

    override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
        configureTransform(width, height)
    }

    override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
        return true
    }

    override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {

    }
}

我的CameraActivity onCreate,onResume()和onPause():

override fun onCreate(savedInstanceState: Bundle?) {
                super.onCreate(savedInstanceState)

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (!canAccessCamera() || !canRecordAudio()) {
                        requestPermissions(INITIAL_PERMISSIONS, INITIAL_REQUEST)
                    }
                }
            }

    override fun onResume() {
            super.onResume()
            cameraHandler.startHandler()
        }

    override fun onPause() {
            cameraHandler.stopHandler()
            super.onPause()
        }

在CameraActivity中检查权限

@RequiresApi(api = Build.VERSION_CODES.M)
    private fun canAccessCamera() : Boolean {
        return (hasPermission(android.Manifest.permission.CAMERA))
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private fun canRecordAudio() : Boolean {
        return (hasPermission(android.Manifest.permission.RECORD_AUDIO))
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private fun hasPermission(perm : String) : Boolean{
        return (PackageManager.PERMISSION_GRANTED == checkSelfPermission(perm))
    }

    @RequiresApi(Build.VERSION_CODES.M)
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == INITIAL_REQUEST) {
            if (canAccessCamera() && canRecordAudio()) {
                recordButton2.setOnClickListener {
                    if (isRecording) {
                        cameraHandler.endRecording()
                    } else {
                        currentFileName = generateTimestampName()
                        createCSVFile(currentFileName)

                        cameraHandler.startStopRecording()
                    }

                    isRecording = !isRecording
                }
            } else {
                Toast.makeText(this, "We need it to perform magic", Toast.LENGTH_SHORT).show()
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

为了这个目的,我自己写了一点PermissionRequestHandler,你可以在这里找到它:https://gist.github.com/Hikaru755/0ae45a4184bdbc28dcc5c1af659b4508

您只需在Activity中创建一个实例,并确保对onRequestPermissionsResult的任何调用都传递给它,就像在gist中的示例BaseActivity中一样。然后你可以将它传递给其他类,通过它请求权限并在你需要的地方获得回调,而不会使你的Activity混乱。但是,请注意不要通过保持比活动生命更长的时间来创建内存泄漏!