When supporting both orientations, leverage ViewModel combined with DataBinding two-way binding to manage UI component data and states. Store text content, click handlers, visibility flags, and other UI properties within the ViewModel. This approach eliminates the need to serialize large amounts of data into Bundles during configuration changes.
Orientation handling encompasses several complex concerns: Activity and Fragment recretaion, managing old Fragment state associations, coordinating lifecycle callbacks, preventing memory leaks from background operations like network requests that could prevent Activity destruction, preserving UI state such as button states and text input across rotations, and dynamically switching between landscape and portrait layouts. A comprehensive architectural approach is essential.
Approach One: Allow Activity and Fragment recreation during orientation changes while implementing MVVM with two-way binding to ensure consistent data display after rotation. The trade-off is that new objects are instantiated on each orientation change, requiring careful memory management.
Approach Two: Prevent Activity rotation by setting configChanges attributes. A single Fragment manages both orientations by including two layout sets within one XML file, with visibility controlled programmatically. Implement orientation switching logic in onConfigurationChanged() to show and hide appropriate layouts. UI state and text are controlled through the ViewModel, ensuring corresponding components maintain synchronized states across both layouts. This approach supports modular decomposition, allowing dynamic repositioning of components based on orientation. The main advantage is reusing the same Activity/Fragment instance, though a single XML file may grow substantial with complex layouts.
Configuration in AndroidManifest.xml:
<activity
android:name=".ui.OrientationDemoActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="user" />
Fragment implementation to configuration change handling:
class OrientationAwareFragment : BaseFragment<FragmentOrientationBinding, DemoViewModel>() {
override fun getLayoutId(): Int {
return R.layout.fragment_orientation
}
override fun setView() {
mBinding.viewModel = mViewModel
// Initial display based on current orientation
mBinding.portraitContainer.visibility = View.VISIBLE
mBinding.landscapeContainer.visibility = View.GONE
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Respond to orientation changes
when (newConfig.orientation) {
Configuration.ORIENTATION_PORTRAIT -> {
Toast.makeText(requireContext(), "Portrait mode", Toast.LENGTH_SHORT).show()
mBinding.portraitContainer.visibility = View.VISIBLE
mBinding.landscapeContainer.visibility = View.GONE
}
else -> {
Toast.makeText(requireContext(), "Landscape mode", Toast.LENGTH_SHORT).show()
mBinding.portraitContainer.visibility = View.GONE
mBinding.landscapeContainer.visibility = View.VISIBLE
}
}
}
}