I've started exploring CameraX library along with sample app and I've noticed some inconsistency in managing lifecycle.
In this thread I will talk only about preview use case as it is mostly related to lifecycle.
In the sample app, in CameraFragment
, use cases are bound to CameraX
in onViewCreated
and unbound in onDestroyView
. First question is do we have to unbind
use cases if we're passing LifecycleOwner
to bind
method? Can we just bind them in onCreate
and leave lifecycle management to CameraX
?
I've also tried to follow getting started tutorial, where SurfaceTexture
of the TextureView
is just replaced. In the sample app, TextureView
is first removed from parent, then added and then SurfaceTexture
is replaced. Do we have to do that? What is the reason?
Another thing is, in the sample app, use cases are bound from view.post { }
method. I've encountered many issues with this approach, because after fragment is put on the backstack, replaced with another fragment and than than recreated, CameraX logged many messages:
E/CamX: [ERROR][STATS_AEC] aec_led_calibration.cpp:560: aec_led_cal_apply_calibration Invalid pointer 0x7921174000 0x0
E/CamX: [ERROR][STATS_AEC] aec_set.cpp:1346: aec_set_fps_range Aec_Error invalid input 414 E/CamX: [ERROR][STATS_AEC] camxcaecstatsprocessor.cpp:1671 SetAlgoBayerHistValue() Unsupported bayer hist channel!
E/CamX: [ERROR][STATS ] camxcaecstatsprocessor.cpp:3194 ProcessRequestFastAE() [FastAE] Failed to apply gain to the stats! E/CamX: [ERROR][STATS_AEC] aec_process.cpp:1229: aec_process_stats_parsing aec is null or invalid
E/CamX: [ERROR][STATS_AEC] aec_process.cpp:7983: aec_process_preview_and_video Error: invalid stats
Is it ok to just set OnPreviewOutputUpdateListener
instead of binding all use cases?
Edit
To show the exact problem, I've created simple project Camera Playground.
Here is CameraFragment
with whole logic.
class CameraFragment : Fragment() {
private val preview by lazy {
val configuration = PreviewConfig.Builder().build()
Preview(configuration)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
CameraX.bindToLifecycle(this, preview)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_camera, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button_gallery.setOnClickListener {
requireActivity().supportFragmentManager
.beginTransaction()
.replace(R.id.container, GalleryFragment())
.addToBackStack("GalleryFragment")
.commit()
}
preview.setOnPreviewOutputUpdateListener { texture_view.surfaceTexture = it.surfaceTexture }
}
}
Now after clicking gallery button, CameraFragment
is replaced with GalleryFragment
. After pressing back button and returning to CameraFragment
, CameraX logs such messages:
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS ] gcamfastaeutil.cpp:1170 SetTuningData() [FastAE] ERROR! Failed to get the tuning data
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][HAL ] camxmetadatapool.cpp:1447 GetMetadataByTag() Invalid Slot to get a metadata from
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][HAL ] camxmetadatapool.cpp:1447 GetMetadataByTag() Invalid Slot to get a metadata from
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS_AEC] aec_led_calibration.cpp:560: aec_led_cal_apply_calibration Invalid pointer 0x7920f1d000 0x0
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS_AEC] aec_set.cpp:1346: aec_set_fps_range Aec_Error invalid input 0
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS ] camxae.cpp:2203 AECSetSensorInfo() Wrong initial sequence from HAL!
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS_AEC] aec_get.cpp:777: aec_get_param GET_EXP_PARAMS ERROR, Uninitialized exposure settings requested
2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][HAL ] camxmetadatapool.cpp:1447 GetMetadataByTag() Invalid Slot to get a metadata from