Представление во фрагменте иногда равно нулю

#android

Вопрос:

У меня есть фрагмент, который запускает камеру и показывает, что камера видит в предварительном просмотре. Я видел на базе, что я получил ошибку:

 Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.Display.getRotation()' on a null object reference
       at com.name.app.maincontroller.CameraActivityFragment.startCamera$lambda-1(CameraFragment.kt:137)
       at com.name.app.maincontroller.CameraActivityFragment.$r8$lambda$Baw0zungVg9sQysXA5zq_tOQHPI()
       at com.name.app.maincontroller.CameraActivityFragment$ExternalSyntheticLambda1.run(:4)
 

Сообщение об ошибке довольно четкое, функция, которая выходит из строя, выглядит так:

 private fun startCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
    cameraProviderFuture.addListener({
        // Used to bind the lifecycle of cameras to the lifecycle owner
        cameraProvider = cameraProviderFuture.get()
        cameraProvider.unbindAll()
        // Set up the view finder use case to display camera preview
        preview = Preview.Builder()
            .setTargetRotation(cameraPreview.display.rotation)  // <- This crashes
            .build()
        try {
            bindVideoCapture()
        } catch (exc: Exception) {
            Log.e("TestCameraPytorch", "Use case binding failed", exc)
        }
        preview.setSurfaceProvider(cameraPreview.surfaceProvider)
    }, ContextCompat.getMainExecutor(requireContext()))
}
 

Я следовал некоторым руководствам по запуску камеры и т. Д., Код, вероятно, не идеален.

cameraPreview устанавливается здесь:

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    cameraCaptureButton = view.findViewById(R.id.camera_capture_button)
    cameraPreview = view.findViewById(R.id.camera_preview)
    setRecordVideoListener()
}  
 

Что может сделать представление нулевым?

Другое дело, что in startCamera val cameraProvider является локальным, но ему назначен слушатель. Это действительно хорошо? Такое ощущение cameraProvider , что у него должна быть более длительная жизнь.

Ответ №1:

Попробуйте создать все ссылки, зависящие от представления, пока вы знаете, что они доступны, поскольку вы создаете их при обратном вызове, нет гарантии, что фрагмент находится в приемлемом состоянии жизненного цикла, чтобы предоставить вам эти ссылки. т. е. cameraPreview Если камера связана жизненным циклом фрагментов, она должна быть стабильной, когда она использует эти ссылки, зависящие от вида. т. е. preview

 private fun startCamera() {
    preview = Preview.Builder()
            .setTargetRotation(cameraPreview.display.rotation)
            .build()
    preview.setSurfaceProvider(cameraPreview.surfaceProvider)
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
    Futures.addCallback(
       cameraProviderFuture, 
       new FutureCallback<ProcessCameraProvider>() {
              fun onSuccess(provider: ProcessCameraProvider) {
                  provider.unbindAll()
                  try {
                     bindVideoCapture()
                  } catch (exc: Exception) {
                     Log.e("TestCameraPytorch", "Use case binding failed", exc)
                  }
              }
              fun onFailure(t : Throwable) {
                  reportError(t)
              }
      },
      ContextCompat.getMainExecutor(requireContext()))
}
 

Комментарии:

1. Спасибо за ответ. Я попробовал это сделать, но потом он начал все время падать, так как все время cameraPreview.display был нулевым. Как это может произойти?

2. Если я переключусь на cameraPreview.rotation.toInt() него, он будет работать на моем телефоне.

3. Версия в моем вопросе работает на моем телефоне, но на телефоне друга она выходит из строя.

4. Может быть, даже не следует использовать дисплей, я думаю, следуя какому-то примеру из Pytorch.