Android M запрашивает разрешение в onSurfaceTextureAvailable callback не в действии

Признаки : при первом запуске приложения происходит сбой с помощью java.lang.SecurityException: Lacking privileges to access camera service . Я получаю диалог «К сожалению, ваше приложение разбилось», нажав «ОК», в этом диалоговом окне есть два диалога с запросом необходимых разрешений. Я говорю «ОК» и с того, и с того момента, как работает приложение. Следующие старты без крушения.

Причины : после некоторого времени чтения и отладки я пришел к пониманию, что проблема с моим приложением заключается в том, что он хочет сделать некоторую логику, связанную с камерой, прежде чем он получит требуемые разрешения ( onSurfaceTextureAvailable callback в моем классе CameraHandler) или до того, как поверхность камеры появится на переднем плане.

Есть много вопросов относительно подобных ошибок в SO и Github, но мне все же сложно понять.

Я попытался пройти этот ответ, но моя настройка немного отличается, т.е. у меня есть моя логика камеры внутри другого класса, которая не является Activity, и я бы очень хотел сохранить ее таким образом, чтобы не загромождать класс CameraActivity. Есть ли хороший способ справиться с этим?

Как убедиться, что, когда onSurfaceTextureAvailable в моем классе CameraHandler запущен, разрешения уже предоставлены, так что я не получаю java.lang.SecurityException: Lacking privileges to access camera service при первом запуске?

Это мой SurfaceTextureListener, расположенный в классе CameraHandler:

  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() } } } 

Я написал себе немного PermissionRequestHandler именно для этой цели, вы можете найти его здесь: https://gist.github.com/Hikaru755/0ae45a4184bdbc28dcc5c1af659b4508

Вы просто создаете экземпляр его в своей деятельности и убедитесь, что к onRequestPermissionsResult передаются любые вызовы onRequestPermissionsResult , как в примере BaseActivity в gist. Затем вы можете передать его другим классам, запросить разрешение через него и получить обратные вызовы там, где они вам нужны, без загромождения вашей деятельности. Будьте осторожны, чтобы не создавать утечки памяти, удерживая их дольше, чем активность.