Jetpack Compose Side Effects & Effect Handlers -II

Abdullaherzincanli
Huawei Developers
Published in
6 min readApr 11, 2023
Source

Hi!šŸ– In this article, we will focus on side effects that can be a headache for our application and Effect Handlers that Jetpack Compose provides us to deal with them.

This article will be the second in our series, and it would be better to read the first article of the series to understand the subject better. In this article, we will continue with the effect handler types that we started in our first article. So letā€™s get started!šŸ§‘šŸ»ā€šŸš€

RememberCoroutineScope

RememberCoroutineScope is a feature of the Kotlin Coroutine framework, which is part of the Compose UI kit. This function is used to create a CoroutineScope object, which allows you to manage operations that run on a separate thread from the UI thread using asynchronous coding techniques.

RememberCoroutineScope helps preserve the state of a CoroutineScope object, allowing it to be maintained during the reordering or iteration of UI elements such as widgets. This ensures that operations are properly managed and prevents unnecessary errors.

Additionally, rememberCoroutineScope automatically cleans up the CoroutineScope object, preventing unnecessary memory usage. Therefore, you do not have to manually clean up the CoroutineScope object, and the performance of the application improves.

Letā€™s provide an example usage with an API request.

Example for RememberCoroutineScope

In this example, a new CoroutineScope object is created with rememberCoroutineScope. Then, a process that needs to be executed in a separate thread is initiated by clicking on the Button widget. This process makes an API request with the help of RetrofitInstance and stores its result in the apiResult mutableStateOf object.

As a result, with the help of Composeā€™s rememberCoroutineScope feature, managing long-running processes such as network operations like API calls becomes easier and provides a more efficient development experience.

Source

RememberUpdatedState

Compose provides some data structures to manage the dynamically changing state of applications, and one of these data structures is the rememberUpdatedState function. The functionā€™s feature is to track a change count whenever any changes are made. This count is used to keep track of when the value was last changed.

We will design an application where the user can select the radius and color of a circle. When selections are made, the area and circumference of the circle will be calculated, and the rememberUpdatedState function will track the radius and color selections and ensure that the component is redrawn even when changes occur. Letā€™s create a code snippet that fits our scenario.

Example for RememberUpdatedState

In this example, the rememberUpdatedState function tracks the radius and color variables and ensures that the component is redrawn when they are modified. The calculateArea and calculateCircumference functions are the ones that perform the calculations and are cached using the remember function. This ensures that the calculations are not recomputed when the radius changes, providing a faster application experience.

ProduceState

The produceState function is used in Jetpack Compose to manage the production and consumption of state values. This function is used to return a coroutine scope along with a state value. The MutableState class represents a modifiable state value. This value is modified by the producer and read by the consumer.

For example, letā€™s say you want to change the background color based on the color selected by the user while developing an application. This is an operation where you need to keep track of the userā€™s selection as a variable and its state on the UI. The produceState feature can help you manage this operation. Letā€™s examine this example in code šŸ•µļø.

Example for ProduceState

In this code snippet, a backgroundColor mutableStateOf object is created using produceState. This object changes the background color according to the color selected by the user. produceState allows calculations in the background to be performed asynchronously, which can lead to performance improvements.

Furthermore, the object created using produceState functions as a stream object and can therefore be used within a stateFlow.collect {} block. For example, if you want to display a message every time the background color changes, you can handle this message within the stateFlow.collect {} block.

The produceState feature is a very powerful feature that you can use when dynamic state management is required in your application. The above example provides a small but powerful use case for state management.

DerivedStateOf

DerivedStateOf allows creating a state object that is derived based on a specific input state. This feature is useful in cases where multiple states are interdependent.

DerivedStateOf acts as a lambda function that takes one or more state objects as input. The lambda function uses one or more input states to create a new derived state object.

Letā€™s create an example application that allows sorting a product list in different ways and changing the background color based on the selected sorting method. In this example, the variable that holds the possibilities for sorting the product list and the product list itself are interdependent. First, letā€™s look at our example and then Iā€™ll explain it to you.

Example for DerivedStateOf

The SortedItems state object is derived using derivedStateOf from the sortOrder and items state objects. The sortedItems variable is automatically updated when sortOrder or items changes and sorts the items according to the new sorting order.

In addition, the background color of each item is determined based on the sortedItems state object. This means that when the sorting order of the items is changed, the background colors are also automatically updated.

In this example, the derivedStateOf function is a powerful feature that can be used for situations where multiple state objects are dependent on each other. If you encounter similar situations in your application, you can use derivedStateOf to write cleaner and more modular code.

Snapshotflow

SnapshotFlow is used to calculate the difference between the previous and current state using flows. It is a helper class provided by Compose and can be used to create flows that monitor state objects.

When subscribing to a flow, SnapshotFlow takes a snapshot of the current state and then watches for any changes in that state. If the state changes, it takes a new snapshot and calculates the difference between the new and previous snapshots. This allows for improved performance by only redrawing the parts that have changed.

Source

Letā€™s create a color picker application together where we set the selected color as the background color every time we choose a color from the palette.

Example for snapShotFlow

In this example, a color picker component named ColorPicker is created. A mutableState object named selectedColor holds the selected color.

Using snapShotFlow, a flow dependent on the selectedColor state object is created. This flow is created by transforming the selected colors into a flow. The collectAsState function is used to store the last selected color state object. This object is used as the background color.

The Box component is set as the background color using the lastSelectedColor object. Additionally, it is made clickable and selects the next color in the list with each click.

This example demonstrates the use of SnapshotFlow to get colors from a dynamic data source instead of a static list.

Conclusion

With this article, we have come to the end of our series. I tried to show you how we can increase the smoothness of our applications with small structural tricks. As developers, when we test our applications, we tend to be cautious in areas where we know their flaws and often passively fix those flaws. šŸ¤¦ā€ā™‚ļø But things donā€™t work like that in real life, and the user doesnā€™t wait for the data to download in the background as you expect. These situations often come back to us as disappointing feedback. Because as developers, we actually know the cumbersome structure there. I think this topic will be of great benefit to us in avoiding such situations. I hope you enjoyed it too. Goodbye, see you in another series šŸ™‹ā€ā™‚ļø.

References

--

--