0

I want to capture image and save to a file using CameraX library. I captured image and save. The image file's size is 0B. I don't know where i went wrong. Logs says this error:

    androidx.camera.core.ImageCaptureException: Not bound to a valid Camera [ImageCapture:androidx.camera.core.ImageCapture-52180692-0099-40c3-8d17-508e08019b84] 

Here is my capture code :

fun bindPreview(
    lifecycleOwner: LifecycleOwner,
    previewView: PreviewView,
    cameraProvider: ProcessCameraProvider,
){
    val preview = Preview.Builder()
        .build().also {
            it.setSurfaceProvider(previewView.surfaceProvider)
        }

     imageCapture = ImageCapture.Builder().build()

    val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

    try {
      cameraProvider.unbindAll()

      cameraProvider.bindToLifecycle(
            lifecycleOwner, cameraSelector, preview, imageCapture)
    }catch(exception: Exception) {
        Log.e(TAG, "Use case binding failed", exception)
    }

}

fun onImageCaptureClicked(context: Context){
        outputDirectory = getOutputDirectory(context)

        val photoFile = File(outputDirectory,  SimpleDateFormat(FILENAME_FORMAT, Locale.US
        ).format(System.currentTimeMillis()) + ".jpg")

        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        imageCapture.takePicture(
            outputOptions, ContextCompat.getMainExecutor(context), object :ImageCapture.OnImageSavedCallback{
                override fun onError(exception: ImageCaptureException) {
                    Log.e( TAG, "Photo capture failed: ${exception.message}", exception)
                }
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(photoFile)
                    val msg = "Photo capture succeeded: $savedUri"
                    Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
                    Log.d(TAG, msg)
                }
            }
        )
}

What should i do?

tametahh
  • 85
  • 6
  • Does this answer your question? [camerax "Not bound to a valid Camera" for imageCapture use case on Android 11](https://stackoverflow.com/questions/64870374/camerax-not-bound-to-a-valid-camera-for-imagecapture-use-case-on-android-11) – dwb Feb 28 '21 at 17:57
  • 1
    Yes, I looked but it didn't help – tametahh Feb 28 '21 at 18:51
  • What device are you seeing this issue on? And are you encountering the same issue on different devices? – Husayn Hakeem Mar 01 '21 at 03:48
  • i am seeing on android 10, api level 30 device. I am also trying m51 with android 10 and api level 31. I get the same error again – tametahh Mar 01 '21 at 06:19

1 Answers1

0

I Used Fragment For CameraX In My Project:

package com.example.splashscreenkotlin.fragments

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.example.splashscreenkotlin.R
import com.example.splashscreenkotlin.databinding.FragmentCameraBinding
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


class CameraFragment : Fragment() {

    private var binding: FragmentCameraBinding? = null
    private val _binding get()  = binding!!
    private var imageCapture: ImageCapture? = null
    private lateinit var mContext: Context
    private lateinit var outputDirectory: File
    private lateinit var cameraExecutor: ExecutorService

    override fun onAttach(context: Context) {
        super.onAttach(context)
        mContext = context
    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentCameraBinding.inflate(layoutInflater,container,false)
        return _binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        outputDirectory = getOutputDirectory()
        cameraExecutor = Executors.newSingleThreadExecutor()

        when{
            allPermissionGuaranted() -> {
                startCamera()
            }
            shouldShowRequestPermissionRationale("permission") -> {
                // In an educational UI, explain to the user why your app requires this
                // permission for a specific feature to behave as expected. In this UI,
                // include a "cancel" or "no thanks" button that allows the user to
                // continue using your app without granting the permission.
            }
            else -> {
                // You can directly ask for the permission.
                requestPermissions(
                    REQUIRED_PERMISSIONS,
                    REQUEST_CODE_PERMISSIONS
                )
            }
        }

        _binding.cameraButton.setOnClickListener {
            takePhoto()
        }

    }

    private fun allPermissionGuaranted() =
        REQUIRED_PERMISSIONS.all {
            ContextCompat.checkSelfPermission(
                mContext,it
            ) == PackageManager.PERMISSION_GRANTED
            // You can use the API that requires the permission.
        }

    private fun startCamera() {
        val cameraProviderFuture = ProcessCameraProvider.getInstance(mContext)
        cameraProviderFuture.addListener({
            val preview = Preview.Builder().build().also { mPreview ->
                mPreview.setSurfaceProvider(_binding.camera.surfaceProvider)
            }

            imageCapture = ImageCapture.Builder().build()

            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA

            try {
                cameraProviderFuture.get().unbindAll()
                cameraProviderFuture.get().bindToLifecycle(
                    this,cameraSelector, preview, imageCapture
                )
            }catch (e:Exception){
                Log.d(TAG,"Camera Start Fail",e)
            }
        },ContextCompat.getMainExecutor(mContext))
    }

    @Deprecated("Deprecated in Java")
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray) {

        when(requestCode == REQUEST_CODE_PERMISSIONS){

            allPermissionGuaranted() -> {
                startCamera()
            }
            else -> {
                Toast.makeText(mContext,"Permission Not granted by the User",Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun getOutputDirectory(): File{
       val mediaDir = activity?.externalMediaDirs?.firstOrNull()?.let { mFile ->
           File(mFile, resources.getString(R.string.app_name)).apply {
               mkdirs()
           }
       }

        return if(mediaDir !=null && mediaDir.exists())
            mediaDir else activity?.filesDir!!
    }

    private fun takePhoto(){
        val imageCapture = imageCapture?: return
        val photoFile = File(
            outputDirectory,
            SimpleDateFormat(File_Name_Format, Locale.getDefault())
                .format(System
                    .currentTimeMillis())+ ".jpg")

        val outputOptions = ImageCapture.OutputFileOptions
            .Builder(photoFile).build()

        imageCapture.takePicture(
            outputOptions, ContextCompat.getMainExecutor(mContext),
            object : ImageCapture.OnImageSavedCallback{
                override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(photoFile)
                    val msg = "Photo Saved"
                    Toast.makeText(mContext,"${msg}, $savedUri",Toast.LENGTH_LONG).show()
                }

                override fun onError(exception: ImageCaptureException) {
                    Log.e(TAG,"onError: ${exception.message}",exception)
                }
            }
        )

    }


    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
        cameraExecutor.shutdown()
    }

    companion object {
        const val TAG = "CameraX"
        const val File_Name_Format = "yyyy-MM-dd-HH-mm-ss-SS"
        const val REQUEST_CODE_PERMISSIONS = 200
        val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
    }

}

Sorry I didnt write Instructions but if u didn't know something and why I write it just text me I'm here to help Also Don't forget Permissions in Manifest And Adding Dependencies of CameraX U can find it in android developers page