Febri
Febri

Reputation: 1

Error when user enable camera permission : java.lang.IllegalStateException: Method setCurrentState must be called on the main thread

I have an Activity which is a camera. In that activity, there is permission before using the camera, but there is a problem when the user allows the use of the camera, namely the application will return to the previous page. When the user returns to the activity, only then can the camera be used properly.

I found a clue to the problem via logcat : java.lang.IllegalStateException: Method setCurrentState must be called on the main thread

My assumption is that setCurrentState (setupCamera) is not on the main thread, but I have tried various ways to make setupCamera conditional on the main thread.

class KameraActivity : AppCompatActivity() {

    private lateinit var classifier: ClassificationFromCamera
    private lateinit var binding: ActivityKameraBinding

    private val executor = ThreadPoolExecutor(
        2, 
        2,
        0L, 
        TimeUnit.MILLISECONDS, 
        LinkedBlockingQueue() 
    )

    @SuppressLint("MissingPermission")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityKameraBinding.inflate(layoutInflater)
        setContentView(binding.root)

        classifier = ClassificationFromCamera(assets)

        if (hasCameraPermission()) {
            setupCamera()
        } else {
            requestCameraPermissions()
        }
    }

    private fun requestCameraPermissions() {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.CAMERA),
            REQUEST_CAMERA_CODE
        )
    }

    @SuppressLint("MissingPermission", "SetTextI18n")
    private fun setupCamera() {
        binding.camera.addPictureTakenListener { imageData ->
            executor.execute {
                val recognitions = classifier.recognize(imageData.data)
                val txt = recognitions.joinToString(separator = "\n\n\n\n")

                runOnUiThread {
                    binding.tvHasil1.text = txt
                }
            }
        }
        binding.capturePhoto.setOnClickListener {
            binding.camera.capture()
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if (requestCode == REQUEST_CAMERA_CODE) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                setupCamera()
            } else {
                Toast.makeText(
                        this,
                        "Aplikasi perlu izin penggunaan kamera",
                        Toast.LENGTH_LONG
                ).show()
                requestCameraPermissions()
            }
        }
    }


    @SuppressLint("MissingPermission")
    override fun onResume() {
        super.onResume()
        if (hasCameraPermission()) {
            binding.camera.start()
        }
    }

    override fun onPause() {
        if (hasCameraPermission()) {
            binding.camera.stop()
        }
        super.onPause()
    }

    override fun onDestroy() {
        if (hasCameraPermission()) {
            binding.camera.destroy()
        }
        super.onDestroy()
    }

    private fun hasCameraPermission() =
        ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED

    companion object {
        private const val REQUEST_CAMERA_CODE = 1
    }
}

However, the problem that I got has not been solved. Previously I had tried using Mainscope, Globalscope, and coroutines. Help me solve this problem.

Upvotes: 0

Views: 141

Answers (1)

ItzDavi
ItzDavi

Reputation: 1078

This is probably beacause of a wrong Dispatcher. Try this

@SuppressLint("MissingPermission", "SetTextI18n")
private fun setupCamera() {
    binding.camera.addPictureTakenListener { imageData ->
       launch(Dispatchers.Main) {
          ...
       }
       
       OR
       
       launch(Dispatchers.Default) {
          ...
       }
    }
    binding.capturePhoto.setOnClickListener {
        binding.camera.capture()
    }
}

And since you are using Kotlin, I can assure you can acheive everything (almost) you need using Coroutines!

Upvotes: 0

Related Questions