All my CameraX initializations reside in FragmentA
, and my goal is to navigate to FragmentB
depending on some condition that must be verified inside analyze()
.
When navigating directly from analyze()
, through Logcat I can see that FragmentB
is loaded correctly but the UI freezes on the camera preview, and unfreezes only when I navigate back to FragmentA
. I discovered that under those circumstances FragmentA
doesn't go through the rest of its lifecycle correctly, meaning that onDestroyView()
and the other methods are called only when I navigate back to it, before immediately beginning a new lifecycle; this leads to cameraExecutor.shutdown()
not being called when it's required.
Edit: I updated the code to reflect my latest attempts at finding a solution. I've added a proper callback which at least looks nicer than what I was doing before, but it still doesn't help.
Out of curiosity I've added a Button
beside CameraX PreviewView
in FragmentA
's layout, so that it calls findNavController().navigate()
. Lo and behold, clicking directly on it makes it all work as expected, but unfortunately I must do it programmatically without any user input. And if I simulate the button click by calling Button#callOnClick()
or Button#performClick()
from within the callback it doesn't work again.
class MyAnalyzer(private val callback: () -> Unit) : ImageAnalysis.Analyzer {
override fun analyze(imageProxy: ImageProxy) {
if (foo) {
imageProxy.close()
callback()
}
// do other stuff with imageProxy...
imageProxy.close()
}
}
class FragmentA : Fragment() {
// rest of the code...
private lateinit var cameraExecutor: ExecutorService
override fun onDestroyView() {
super.onDestroyView()
Log.d(TAG, "executor shutdown")
cameraExecutor.shutdown()
Log.d(TAG, "FragmentA destroyed")
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
cameraExecutor = Executors.newSingleThreadExecutor()
val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
cameraProviderFuture.addListener(Runnable {
// other CameraX code...
val imageAnalysis = ImageAnalysis.Builder()
.setTargetRotation(rotation)
.build()
.also {
it.setAnalyzer(
cameraExecutor, MyAnalyzer({
findNavController().navigate(R.id.action_fragmentA_to_fragmentB)
})
)
}
// bind to lifecycle of use cases
}, ContextCompat.getMainExecutor(requireContext()))
}
question from:
https://stackoverflow.com/questions/65834355/navigating-to-another-fragment-from-camerax-analyze-blocks-current-fragments 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…