【问题标题】:Kotlin CameraX can't capture imageKotlin CameraX 无法捕获图像
【发布时间】:2022-04-09 09:44:21
【问题描述】:

我想使用 CameraX 库捕获图像并保存到文件中。我捕获了图像并保存。图像文件的大小为 0B。我不知道我哪里错了。日志显示此错误:

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

这是我的捕获代码:

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

我该怎么办?

【问题讨论】:

  • 是的,我看了,但没有帮助
  • 您在什么设备上看到此问题?您是否在不同的设备上遇到过同样的问题?
  • 我在 android 10,api 级别 30 设备上看到。我也在尝试使用 android 10 和 api 级别 31 的 m51。我再次遇到同样的错误

标签: android kotlin android-camerax


【解决方案1】:

我在我的项目中为 CameraX 使用了 Fragment:

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

}

对不起,我没有写说明,但如果你不知道什么以及我为什么写它,请发短信给我,我在这里为您提供帮助 也不要忘记 Manifest 中的权限和添加 CameraX 的依赖项 你可以在android开发者页面找到它

【讨论】:

    猜你喜欢
    • 2021-01-06
    • 2022-01-06
    • 2020-09-04
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多