Understanding Composition Local: Jetpack Compose
As we dive deeper into the world of Jetpack Compose, it’s essential to explore the powerful tools. One such tool is CompositionLocal.
To understand CompositionLocal, lets first understand:
Data Flow in Composable
- In Jetpack Compose, data flows down through the composition tree.
- Each parent composable passes necessary data explicitly to their children.
- For data used by multiple composables, passing the same data along the tree can become cumbersome.
Here Comes CompositionLocal
- CompositionLocal allows the creation of objects available throughout the entire UI tree or specific subtrees.
- It eliminates the need to pass data explicitly through all composables, making data implicitly available.
Lets have a look at some of the widely used Composition Local:
Predefined CompositionLocals
Jetpack Compose comes with several predefined CompositionLocal objects that facilitate common use cases.
1. LocalContext
This provides the current Android context. It’s often used when you need to access Android-specific APIs.
val context = LocalContext.current
Toast.makeText(context, "Hello, World!", Toast.LENGTH_SHORT).show()
2. LocalConfiguration
Provides the current configuration (e.g., screen size, orientation).
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp
when (configuration.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
Text("Landscape : $screenWidth")
}
else -> {
Text("Portrait : $screenWidth")
}
}
3. LocalLifecycleOwner
Provides the LifecycleOwner of the current composition. This is useful for observing lifecycle events.
val lifecycleOwner = LocalLifecycleOwner.current
lifecycleOwner.lifecycle.addObserver(MyObserver())
4. LocalDensity
Provides density information which can be used to convert between dp, sp, and px.
val density = LocalDensity.current
val paddingInPx = with(density) { 16.dp.toPx() }
5. LocalLayoutDirection
Provides the current layout direction (LTR or RTL).
val layoutDirection = LocalLayoutDirection.current
6. LocalViewModelStoreOwner
Provides the ViewModelStoreOwner, for accessing ViewModels within the current scope.
val viewModelStoreOwner = LocalViewModelStoreOwner.current
val homeViewModel: HomeViewModel = viewModel(
key = "HomeViewModel",
viewModelStoreOwner = viewModelStoreOwner
)
User-Defined CompositionLocals
You can define your own to share custom data across your composables. Lets see it with an example.
Step 1: Define the CompositionLocal
In this example, LocalUser is a CompositionLocal that holds a User object.
val LocalUser = compositionLocalOf<User> { error("No user provided") }
Step 2: Define the CompositionLocal
The CompositionLocalProvider is used to provide the User instance to the composables within its scope.
@Composable
fun MyApp() {
val user = remember { User("John Doe") }
CompositionLocalProvider(LocalUser provides user) {
MyScreen()
}
}
Step 3: Consume the CompositionLocal
Any composable within the scope can access the User instance using LocalUser.current.
@Composable
fun MyScreen() {
val user = LocalUser.current
Text(text = "Hello, ${user.name}")
}
Conclusion
- Implicit Data Sharing: Makes data available across composables without explicit passing.
- Cleaner Code: Reduces boilerplate and enhances code readability.
- Lifecycle Management: Ensures proper lifecycle handling for ViewModels and other dependencies.
- Flexible Scoping: Allows different values for different parts of the UI tree.
Thank you for taking the time to read this article. If you found the information valuable, please consider giving it a clap or sharing it with others who might benefit from it.
Any Suggestions are welcome. If you need any help or have questions for Code Contact US. You can follow us on LinkedIn for more updates 🔔