ylliX - Online Advertising Network
Android Interview Series 2024 — Part 7 (Jetpack Compose)

Android Interview Series 2024 — Part 7 (Jetpack Compose)


This is Part 7 of the android interview question series. This part will focus on Jetpack Compose.

1. What is Jetpack Compose?

Jetpack Compose is Android’s recommended modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Jetpack Compose is declarative programming, which means you can describe your user interface by invoking a set of composables, which is vastly different from the traditional way of imperative UI design.

2. How does Jetpack Compose differ from XML-based UI?

  • XML-based UI follows an imperative approach, where you define the UI layout in XML and then programmatically change its properties in the Activity or Fragment as the state changes. Jetpack Compose uses a declarative approach. You define what the UI should look like based on the current state. When the state changes, the UI automatically updates to reflect those changes without requiring manual intervention.
  • Since Jetpack Compose reduces the need for XML and reduces code duplication, you can achieve more with less code. This leads to fewer errors and a more maintainable codebase.
  • Reusability is simpler due to composable functions. You can create UI components as functions with the @Composable annotation and reuse them across different parts of the app, easily adding parameters for customization.
  • Android Studio provides powerful tools for Jetpack Compose, like live previews, which allow you to see how your UI looks in real-time as you code.

3. How can we use traditional android views and compose together?

Embedding XML View insider Jetpack Compose: We can embed a traditional Android View inside a Jetpack Compose layout using the AndroidView composable. This allows to use any existing Android View component within a Compose UI.

Embedding Jetpack Compose in XML Layouts:

4. What is a Composable function, and how do you define one?

A Composable function is a fundamental building block in Jetpack Compose. It’s a special function that defines a piece of UI in a declarative way. By marking a function with @Composable, you make it possible for Jetpack Compose to track and manage the UI it represents, automatically handling updates whenever the underlying data or state changes.

@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}

5. Explain the Jetpack Compose Lifecycle.

The Jetpack Compose Lifecycle is similar to the traditional Android lifecycle but has unique characteristics due to its declarative, reactive nature.

  • Composition is the initial phase where the UI elements are created for the first time.
  • This phase only occurs once for a given part of the UI (unless it needs to be recreated). Once composed, the UI stays on the screen until it is either updated (via recomposition) or removed (via disposal).
  • When a composable function is called for the first time, Jetpack Compose: builds the UI tree by evaluating the composable functions and creating UI elements and adds the resulting UI elements to the screen, establishing the initial view structure.
  • Recomposition is the phase where Jetpack Compose updates the UI in response to state changes.
  • During recomposition, only the functions affected by the state changes are re-evaluated.
  • If no state changes occur, Compose will not recompose.
  • Recomposition happens whenever a value that a composable depends on changes.
  • Disposal is the phase where Compose removes composable functions that are no longer needed from the UI.
  • This typically happens when a composable: goes out of scope due to a change in the UI tree (e.g., navigating away from a screen or conditionally removing a component) or is replaced by another composable.
  • During the disposal phase, Compose: cleans up resources associated with the composable, such as cancelling coroutines, releasing listeners, or disposing of state objects and executes DisposableEffect cleanup code if defined, ensuring no resources are left hanging.

6. What is a Modifier in Jetpack Compose?

A Modifier in Jetpack Compose is a powerful and flexible tool used to modify the appearance, behavior, and layout of composable functions. Modifiers are essential for adding properties like padding, size, background, click actions, and layout adjustments to composable elements without altering the composable function itself.

  • Modifiers are stateless. They do not hold or manage state.
  • Modifiers are chainable. They can be chained to apply multiple properties sequentially, creating a flexible way to build complex UI behaviors.
  • Modifiers are reusable. They are designed to be highly reusable, allowing you to define them once and apply them to multiple composables.

7. What are the different types of Modifier?

Layout modifiers: Layout modifiers control the size, padding, alignment, and general layout behavior of a composable.

  • padding: Adds padding around a composable.
  • fillMaxSize / fillMaxWidth / fillMaxHeight: Makes the composable fill the available space.
  • size: Sets an explicit width and height.
  • wrapContentSize: Wraps the composable’s size to its content and positions it within the available space.
  • align(): modifier specifies the alignment of a composable within its parent layout.
  • weight(): is used in Row or Column layouts to distribute space among children based on their weight.

Appearance modifiers: Appearance modifiers help you modify the look of composables by adding background colors, borders, and opacity.

  • background: Sets a background color.
  • border: Adds a border around the composable.
  • alpha: Adjusts the transparency of a composable.
  • clip: clips the composable to a specified shape.
  • shadow: adds a shadow effect to a composable.

Behaviour modifiers: Behavior modifiers allow you to add interactivity, such as click handling, scroll behavior, and gestures.

  • clickable: Makes the composable respond to click events.
  • scrollable: Adds scroll behavior (e.g., for custom scrollable components).
  • toggleable: adds toggle behavior, useful for creating switch-like components.
  • draggable: allows dragging gestures on the composable.

Animation modifiers: add animations and transitions to composables.

  • animateContentSize: Automatically animates size changes.
  • graphicsLayer: applies transformations such as scaling, rotation, and translation.

Custom modifiers: You can create custom modifiers by defining extension functions on Modifier. This is useful for applying a specific combination of modifiers that you might use frequently.

8. How to create Responsive Layouts with Jetpack Compose?

  • Use Modifier with Adaptive Sizing: Using Modifier functions like fillMaxWidth(), fillMaxSize(), weight(), and wrapContentSize() allows your composables to adapt to the available screen space.
  • Responsive Layouts with ConstraintLayout: ConstraintLayout allows you to create more complex responsive layouts by defining constraints between elements, similar to XML-based ConstraintLayout in Android.
  • BoxWithConstraints allows you to access the constraints of the available space, enabling you to create conditional layouts based on the screen size or orientation.
  • Compose provides WindowSizeClass as a way to categorize screen sizes, making it easy to switch layouts based on the type of device (compact, medium, expanded).

9. How do you handle orientation changes in Jetpack Compose?

Orientation changes in Jetpack Compose are handled automatically by recomposing the UI based on the new configuration. Composable functions that define the UI layout and behavior will be recomposed with the updated configuration, allowing the UI to adapt to the new orientation.

10. How does Recomposition work in Jetpack Compose?

Recomposition is the process by which Jetpack Compose updates parts of the UI when there is a change in state. When a state variable (like a MutableState) changes, Jetpack Compose identifies the composables that depend on that state and re-runs only those composables, updating the UI accordingly. This minimizes the work needed to keep the UI in sync with the underlying data, which improves performance.

11. What is State in Jetpack Compose?

State in Jetpack Compose represents data that can change over time and that Compose uses to update the UI when it changes. It allows the UI to automatically respond to changes in underlying data.

12. What are the two different types of state?

  • Local State: Local state is the state managed within a single composable function. It’s typically used for UI elements that don’t need to share their state with other parts of the UI. Local state is created using remember and mutableStateOf, which retain values across recompositions within the same composable.
  • Shared State: In this pattern, the state is moved up to a shared parent component, making it easier to manage across different parts of the UI.

13. What is state hoisting?

State hoisting is a design pattern in Jetpack Compose that involves moving (or “hoisting”) state out of a composable function and into its parent composable. This approach makes the state “shared” between composables and allows for better reusability, testing, and separation of concerns.

14. What is the purpose of remember in Jetpack Compose?

  • The remember function in Jetpack Compose is used to store a value across recompositions, allowing the value to persist without resetting every time the composable function is recomposed.
  • When you use remember, Compose caches the value during the initial composition. During recomposition, Compose checks the cache and reuses the stored value instead of recalculating or reinitializing it. However, if the composable leaves the composition (like when navigating away from a screen), the value is cleared.

15. Explain rememberSaveable. How is it different from remember?

  • rememberSaveable works similarly to remember, but it preserves its state across configuration changes like screen rotations. It’s useful for UI elements like text fields that need to retain state when the device orientation changes.
  • rememberSaveable: Saves the values in the bundle of the saved instance state (or SavedStateHandle). This enables it to restore the values after configuration changes, though it may incur slight overhead for storing and retrieving data.

16. How does MutableState work in Jetpack Compose?

  • MutableState is an observable data holder that allows composables to react to changes in state automatically. When the value of a MutableState object changes, Jetpack Compose triggers a recomposition for any composables that read that state, updating the UI to reflect the new data.
  • MutableState is typically created using the mutableStateOf function. This function returns an instance of MutableState that holds the initial value and updates the value whenever it changes.

17. Explain the concept of Derived States in Compose.

  • Derived State is a concept used to create a new state based on one or more existing states. It allows you to compute values based on other states, updating only when the underlying state(s) change.
  • The derivedStateOf function is used to create derived states in Compose. This function takes a lambda that computes the derived value and only recomposes when the result of the calculation changes.
  • derivedStateOf works by observing the input state(s) used within its lambda function. When any of the observed input states change, Compose re-evaluates the lambda.

18. What are SideEffects in Jetpack Compose?

In Compose, a side-effect refers to any change in the app’s state that occurs outside the scope of a composable function. Side effects should be executed in a way that respects the composable lifecycle to avoid unexpected behaviors, like duplicate network requests on recomposition. Side effects ensure that actions occur only when necessary and not during every recomposition, keeping the UI efficient and consistent.

19. Explain the different SideEffects in Jetpack Compose?

LaunchedEffect: is used to run suspend functions within the lifecycle of a composable.

  • It triggers a coroutine when the composable enters the composition, making it ideal for tasks like fetching data or handling side-effects based on changes in state.
  • The key parameter in LaunchedEffect is used to identify the LaunchedEffect instance and prevent it from being recomposed unnecessarily.
  • If the value of the key parameter changes, Jetpack Compose will consider the LaunchedEffect instance as a new instance, and will execute the side effect again.
  • DisposableEffect: s used for side effects that require setup and cleanup when the composable enters and exits the composition. It’s often used to manage resources that need explicit cleanup, like registering/unregistering listeners. A key point with DisposableEffect is that it allows you to add and remove observers or listeners in a safe manner that is tied directly to the composable’s lifecycle. This helps prevent memory leaks and ensures that resources are cleaned up when no longer needed.
  • rememberCoroutineScope: When you need a coroutine to start based on a user action, such as a button click, rememberCoroutineScope is useful. It provides a scope tied to the composable’s lifecycle, ensuring the coroutine cancels if the composable leaves the composition.

rememberUpdatedState: is to keep an updated reference to a value within long-lived or side-effect composables, like LaunchedEffect or DisposableEffect, without restarting them when the value changes.

  • It effectively “pins” the latest value, ensuring that ongoing effects can access it without triggering recompositions or re-running the effect.
  • This approach is particularly useful when you have a callback or lambda function passed into a composable that may change over time. You may not want to restart the entire effect when the callback changes, especially if the effect is managing a complex operation like a long-running coroutine.
  • SideEffect runs non-suspendable side effects during each recomposition. It allows you to perform actions that don’t require any cleanup but need to execute whenever a specific recomposition happens. Examples include logging, debugging, or updating external objects that are not tied to Compose’s lifecycle.

20. What are SnapshotStateList and SnapshotStateMap

SnapshotStateList and SnapshotStateMap are special types of collections in Jetpack Compose designed to work efficiently with Compose’s state system. These collections are observable, meaning that when their content changes, they trigger recomposition in any composables that depend on them. They are useful for managing lists and maps in a way that Compose can track changes and update the UI accordingly.

21. What is snapshotFlow, and when would you use it?

snapshotFlow converts state changes within the Compose snapshot system into a Kotlin Flow. It allows you to observe changes to Compose state values in a coroutine-based Flow format, which can then be collected and transformed asynchronously. This is particularly useful when you need to react to state changes in a non-composable function or want to combine, debounce, throttle, or filter state updates in a coroutine context.

22. Describe produceState.

produceState is used to convert external state, such as data from a network or database, into Compose state. It launches a coroutine that updates the state as necessary. This is particularly useful for managing state that is derived from external sources, such as fetching data from a remote API or database and then feeding that data into your composable’s state.

produceState(
// The initial value of the state before any data is produced.
initialValue: T,
// he dependency keys that determine when produceState should restart the coroutine.
// If any of the keys change, the coroutine will be re-launched.
vararg keys: Any?,
// A lambda that contains the suspendable code to produce the state.
producer: suspend ProduceScope<T>.() -> Unit
): State<T>

23. Explain CompositionLocal.

CompositionLocal provides a mechanism for passing data down through the composition implicitly, without needing to pass it through every composable function. This can be particularly useful when the data is frequently used across many parts of the UI, such as theme-related information (like theme, configuration settings, or dependencies).

  • CompositionLocal is similar to dependency injection but is designed specifically for Compose’s composable hierarchy.
  • It allows composables to access “ambient” data, meaning data that is globally available within a certain scope but not explicitly passed down through parameters.
  • CompositionLocalProvider is used to provide values for these locals, and CompositionLocal.current is used to access them.

24. What are the different types of CompositionLocal Providers?

compositionLocalOf is the most commonly used provider for creating a CompositionLocal with a default or fallback value. It’s useful when you want to provide a single value that can be accessed anywhere within the composition tree.

This API allows fine control over recompositions. When the value changes, only the parts of the UI that read this value are recomposed. This makes it ideal for frequently changing data like dynamic themes or user preferences.

staticCompositionLocalOf is similar to compositionLocalOf, but it is optimized for static values that do not change during recomposition. This provider type should be used when the value is guaranteed not to change after it has been set. This is commonly used for values that are initialized once, such as a singleton dependency, app-wide configurations, or services like SharedPreferences.

Jetpack Compose also provides several predefined CompositionLocal objects for common scenarios, like accessing theme values, layout direction, and text input service.

25. How can we manage navigation using Composition Local?

26. How can we dynamically switch themes with the help of CompositionLocal?

27. How can we manage authenticated state of a user with the help of CompositionLocal?

28. Explain the concept of delegation and the by keyword when working with Jetpack Compose.

  • Delegation is a design pattern that allows a class to delegate certain responsibilities to another object or class. This concept is especially useful in Compose when dealing with state management.
  • The by keyword is used to facilitate delegation, making code more concise and readable.
  • Property delegation allows a property to be managed by another object. Instead of manually implementing getter and setter logic, you can “delegate” this responsibility to an object that implements the required functionality.
  • The by keyword in Kotlin specifies that a property’s getter and setter methods are handled by the delegate object. The by keyword is often used with mutableStateOf or remember to delegate state management, allowing Compose to observe changes to the property and trigger recompositions when the property value changes.

29. What are the different optimisation techniques in Jetpack Compose?

  • Using remember to Cache Values Across Recompositions: The remember function caches values across recompositions, preventing the need to recalculate values that don’t change.
  • rememberSaveable extends remember by preserving values across configuration changes, like screen rotations. It’s especially useful for persisting user-entered text or selected options.
  • Compose automatically recomposes only the parts of the UI that depend on updated state. However, to optimize performance, it’s helpful to isolate state-dependent parts of your UI within smaller composable functions.
  • LaunchedEffect is useful for side effects that need to occur only once or when certain keys change. This prevents re-running the effect during every recomposition, which can be resource-intensive.
  • derivedStateOf can be used to avoid redundant calculations by caching derived values. It recalculates only when its dependencies change, optimizing performance for derived properties.
  • When displaying large lists, using LazyColumn and LazyRow is essential. Unlike Column and Row, they only render visible items, which conserves memory and improves performance.
  • snapshotFlow efficiently converts Compose state into a Kotlin Flow. This is ideal for handling continuous state updates without triggering recompositions.
  • Jetpack Compose provides the animateAsState functions for smooth animations with minimal recompositions. Use them for animating properties that are lightweight and do not trigger recompositions on every frame.
  • Using stable data and unique keys in lists helps Compose avoid unnecessary recompositions by ensuring that data changes are detected accurately.
  • When managing resources like listeners or other resources tied to the composable lifecycle, use DisposableEffect for efficient setup and cleanup. This ensures that resources are freed when the composable leaves the composition.

30. Share an example of how we can manage state using ViewModel and LiveData in Compose.

Using ViewModel with LiveData or StateFlow is recommended for managing state across lifecycle events, such as screen rotations, or when state needs to persist beyond the lifecycle of a composable.

31. Share an example of how we can manage state using ViewModel and StateFlow in Compose.

32. Explain the concept of lazy composition in Jetpack Compose.

Lazy composition refers to the concept of deferring the composition of UI elements until they are actually needed or visible on the screen. This approach is particularly useful for handling large collections of UI elements, like lists or grids, by only composing the items that are currently in view. Lazy composition helps optimize performance and memory usage by minimizing the number of composable functions that are composed at any given time.

33. What are Recomposition and Skippable Recomposition?

  • Recomposition is the process in which a composable function re-executes to reflect changes in the underlying state that it depends on. Recomposition works by tracking state reads within a composable function. When a composable reads a state, Compose “subscribes” to that state, and any changes in the state trigger recomposition of that composable.
  • Skippable recomposition is a performance optimization that prevents recomposition of composables when their dependencies haven’t changed.
  • Compose can “skip” recomposing certain parts of the UI if it detects that the values the composable depends on have not changed since the last recomposition.
  • For a composable to be “skippable,” the values it depends on should be stable. In Kotlin, data marked with val and immutable data types are inherently stable.
  • Jetpack Compose considers stable data to be data that is either immutable or marked with @Stable.

34. How to achieve Relative Positioning in Jetpack Compose?

Unlike traditional XML layouts in Android, Jetpack Compose does not have a direct equivalent of RelativeLayout, but it provides composable functions like Box, Row, Column, ConstraintLayout , and alignment modifiers to achieve relative positioning.

  • Using Box for Overlapping Composables: Box is a layout that allows its children to overlap each other, making it useful for positioning items relative to each other with alignment modifiers.
  • Row and Column are great for positioning items horizontally or vertically relative to each other. You can adjust Arrangement and Alignment to control the positioning of each child.
  • Modifier.offset allows you to apply pixel offsets to composables, giving precise control over their position relative to the default layout position.
  • ConstraintLayout provides advanced positioning features, similar to the traditional ConstraintLayout in XML.



Source link

Leave a Reply

Your email address will not be published. Required fields are marked *