Reader small image

You're reading from  Android UI Development with Jetpack Compose - Second Edition

Product typeBook
Published inNov 2023
Reading LevelN/a
PublisherPackt
ISBN-139781837634255
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Thomas Künneth
Thomas Künneth
author image
Thomas Künneth

Thomas Künneth is a Google Developer Expert for Android and has been a speaker and panelist at multiple international conferences about Android. Currently, Thomas works as a senior Android developer at Snapp Mobile. He has authored countless articles as well as one of the top-selling German Android books (currently in its sixth edition). He has also frequently contributed to various open source projects.
Read more about Thomas Künneth

Right arrow

Exploring App Architecture

In Chapter 6, Building a Real-World App, we combined several key techniques of Jetpack Compose, including state hoisting, app theming, and navigation, in a real-world example. ComposeUnitConverter stores state in a ViewModel and eventually persists it using the Repository pattern. In this chapter, I will show you how to pass objects to a ViewModel upon instantiation and use these objects to load and save data. In Chapter 2, Exploring the Key Principles of Compose, we examined features of well-behaved composable functions. Composables should be free of side effects to make them reusable and easy to test. However, there are situations when you need to either react to or initiate state changes that happen outside the scope of a composable function. We will cover this at the end of this chapter.

These are the main sections of this chapter:

  • Persisting and retrieving state
  • Keeping your composables responsive
  • Understanding side effects
...

Technical requirements

Please refer to the Technical requirements section of Chapter 1, Building Your First Compose App, for information about how to install and set up Android Studio, as well as how to get the example apps.

The Persisting and retrieving state and Keeping your composables responsive sections further discuss the example ComposeUnitConverter app of Chapter 6, Building a Real-World App. The Understanding side effects section is based on the EffectDemo example.

Persisting and retrieving state

State is app data that may change over time. In a Compose app, state is typically represented as instances of State or MutableState. If such objects are used inside composable functions, a recomposition is triggered upon state changes. If a state is passed to several composables, all of them may be recomposed. This leads to the state hoisting principle: state is passed to composable functions rather than being remembered inside them.

Please note

Here, passed doesn’t necessarily mean using State<?> or MutableState<?> as parameters of composable functions. As you’ve seen in many of my examples, you can instead pass the current value of the state as an ordinary data type and the code that you want to be executed upon state changes as a callback.

Often, state is remembered in the composable that is the parent of the ones using the state. An alternative approach is to implement an architectural pattern called ViewModel....

Keeping your composables responsive

When implementing composable functions, you should always keep in mind that their main purpose is to declare the UI and to handle user interactions. Ideally, anything needed to achieve this is passed to the composable, including state and logic (such as click handlers), making it stateless. If state is needed only inside a composable, the function may keep state temporarily using remember {}. Such composables are called stateful. If data is kept in a ViewModel, composables must interact with it. So, the ViewModel code must be fast, too.

Communicating with ViewModel instances

Data inside a ViewModel should be observable. ComposeUnitConverter uses StateFlow and MutableStateFlow from the kotlinx.coroutines.flow package to achieve this. You can choose other implementations of the Observer pattern, provided there is a way to obtain State or MutableState instances that are updated upon changes in the ViewModel. This, however, is beyond the scope...

Understanding side effects

In the Using Scaffold() to structure your screen section of Chapter 6, Building a Real-World App, I showed you how to display a snack bar using rememberCoroutineScope {} and snackbarHostState.showSnackbar(). As showSnackbar() is a suspending function, it must be called from a coroutine or another suspending function. Therefore, we created and remembered CoroutineScope using rememberCoroutineScope() and invoked its launch {} function.

Invoking suspending functions

The LaunchedEffect() composable is an alternative approach for spawning a suspending function. To see how it works, let’s look at the LaunchedEffectDemo() composable. It belongs to the EffectDemo example, as illustrated in the following screenshot:

Figure 7.1 – The EffectDemo example showing LaunchedEffectDemo()

Figure 7.1 – The EffectDemo example showing LaunchedEffectDemo()

LaunchedEffectDemo() implements a counter. Once the Start button has been clicked, a counter is incremented every second. Clicking on Restart...

Summary

This chapter covered additional aspects of the ComposeUnitConverter example. We continued the exploration of the ViewModel pattern we began looking at in the Using ViewModel section of Chapter 5, Managing State of Your Composable Functions. This time, we added business logic to the ViewModel and injected an object that can persist and retrieve data.

The Keeping your composables responsive section revisited one of the key requirements of a composable function. Recomposition can occur very often, therefore composables must be as fast as possible, which in turn dictates what the code inside them can and cannot do. I showed you how a simple loop can cause a Compose app to stop responding, and how coroutines are used to counteract this.

In the final main section, Understanding side effects, we examined so-called side effects and used LaunchedEffect and DisposableEffect to implement a simple counter.

In Chapter 8, Working with Animations, you will learn how to show and hide...

Questions

  1. Why can it become necessary to inject an object into your ViewModel?
  2. ViewModels do not expose mutable data, but only read-only properties. How is changing the data implemented?
  3. Why is it considered a bad practice to keep long-running code in a composable function?
  4. What can LaunchedEffect and DisposableEffect be used for?

Exercise

Passing wrong (being too short-lived) Context instances to ViewModels or repositories can lead to unexpected behavior during runtime. By using applicationContext, ComposeUnitConverter makes sure this doesn’t happen. However, in production apps, you should try not to pass the Context, but instead the object that uses the context. Let’s refactor ComposeUnitConverter so that the Repository class constructor receives a SharedPreferences instance. Where do you need to put PreferenceManager.getDefaultSharedPreferences() and what is important to keep in mind? Finally, which other code do you need to adapt once you have refactored the Repository class?

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Android UI Development with Jetpack Compose - Second Edition
Published in: Nov 2023Publisher: PacktISBN-13: 9781837634255
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Thomas Künneth

Thomas Künneth is a Google Developer Expert for Android and has been a speaker and panelist at multiple international conferences about Android. Currently, Thomas works as a senior Android developer at Snapp Mobile. He has authored countless articles as well as one of the top-selling German Android books (currently in its sixth edition). He has also frequently contributed to various open source projects.
Read more about Thomas Künneth