如何在Android中显示使用CameraX拍摄的图像。
我的情况:我有两个片段。在其中一个片段中,我已经实现了CameraX功能以拍摄照片并将其保存到本地。现在我想将这个图像传递给另一个片段,并在那里显示它在一个ImageView中。
最好的方法是什么(如果您可以提供一个有效的代码,那将是很有帮助的)?
我想到解决这个问题的几种方法:
第一种方法:发送从“overriding onImageSaved”中提取的Uri Id(我们在“ImageCapture.OutputFileResults”中获得Uri id)。但是,这种方法存在一些问题。使用Android Navigation将Uri作为bundle或safe args发送时将其显示为空值。这意味着没有跨导航传输Uri。
第二种方法:将uri转换为位图,然后将此位图发送到另一个片段。在那里解码位图以将其放置在ImageView上。我不确定这种方法是否可行,如果您曾经使用过,请让我知道。
还有其他处理此问题的方式吗?我在官方Android文档中找不到任何文章介绍这个问题。
Camera Fragment(第1个片段):
我的情况:我有两个片段。在其中一个片段中,我已经实现了CameraX功能以拍摄照片并将其保存到本地。现在我想将这个图像传递给另一个片段,并在那里显示它在一个ImageView中。
最好的方法是什么(如果您可以提供一个有效的代码,那将是很有帮助的)?
我想到解决这个问题的几种方法:
第一种方法:发送从“overriding onImageSaved”中提取的Uri Id(我们在“ImageCapture.OutputFileResults”中获得Uri id)。但是,这种方法存在一些问题。使用Android Navigation将Uri作为bundle或safe args发送时将其显示为空值。这意味着没有跨导航传输Uri。
第二种方法:将uri转换为位图,然后将此位图发送到另一个片段。在那里解码位图以将其放置在ImageView上。我不确定这种方法是否可行,如果您曾经使用过,请让我知道。
还有其他处理此问题的方式吗?我在官方Android文档中找不到任何文章介绍这个问题。
Camera Fragment(第1个片段):
class CameraFragment : Fragment() {
private var _binding: FragmentCameraBinding? = null
private val binding: FragmentCameraBinding get() = _binding!!
private var imageCapture: ImageCapture? = null
private lateinit var cameraExecutor: ExecutorService
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentCameraBinding.inflate(inflater, container, false)
//Request Camera Permissions
// Request camera permissions
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(
requireActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
)
}
cameraExecutor = Executors.newSingleThreadExecutor()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Setting up listeners for taking Photo
binding.imageCaptureButton.setOnClickListener {
takePhoto()
}
}
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time stamped name and MediaStore entry.
val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions
.Builder(
requireContext().contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
.build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(requireContext()),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Timber.e("Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val msg = "Photo capture succeeded: ${output.savedUri}"
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
Timber.d(msg)
val uriFilePath = output.savedUri?.path
val path: String = uriFilePath.toString()
val bundle = Bundle()
bundle.putString("image", path)
Navigation.findNavController(requireView()).navigate(R.id
.cameraFragmentToCameraFinalFragment, bundle)
}
})
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
requireContext(), it
) == PackageManager.PERMISSION_GRANTED
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.build()
.also { preview ->
preview.setSurfaceProvider(binding.viewFinder.surfaceProvider)
}
imageCapture = ImageCapture.Builder()
.build()
val imageAnalyzer = ImageAnalysis.Builder()
.setTargetResolution(Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
.also {
it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
Timber.d("Average luminosity: $luma")
})
}
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture, imageAnalyzer
)
} catch (exc: Exception) {
Timber.e("Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(requireContext()))
}
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults:
IntArray
) {
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startCamera()
} else {
Toast.makeText(
requireContext(), "Permissions not granted by the user.",
Toast.LENGTH_SHORT
).show()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
cameraExecutor.shutdown()
}
companion object {
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = mutableListOf(
Manifest.permission.CAMERA,
).apply {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
}.toTypedArray()
}
}
PhotoFinalFragment(第二个片段):
class PhotoFinalFragment : Fragment() {
private var _binding: FragmentPhotoFinalBinding? = null
private val binding: FragmentPhotoFinalBinding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
_binding = FragmentPhotoFinalBinding.inflate(inflater, container, false)
val bundle: Bundle? = arguments?.getBundle("image")
val uri: Uri = bundle?.get("image") as Uri
binding.imageView.setImageURI(uri)
binding.btnYes.setOnClickListener {
Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentToStoryFragment)
}
binding.btnNo.setOnClickListener {
Navigation.findNavController(requireView()).navigate(R.id.cameraFinalFragmentTocameraFragment)
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}