This is the first day of my participation in the August Challenge. For details, see:August is more challenging

Two years in the making, the Android team has launched a new native Android UI library called Compose. Compose, of course, is also part of the Jetpack tool library, which officially claims to simplify and speed up interface development on Android, allowing you to quickly build lively and exciting apps with less code. Version 1.0 was just released at the end of last month and is now available in production! Anyway, take a look!

1. How much does it cost to get started?

Personal feeling, still ok, have certain study cost. A prerequisite is familiarity with the Kotlin language, which is used for Compose, and even better with the other Jetpack libraries.

Compose can interoperate with existing engineering projects. For example, we can put the Compose UI in the View of our existing layout, or we can put the View in the Compose UI.

As part of the Jetpack tool library, Compose can also be easily integrated with LiveDada, ViewModel, Paging and other tools to improve coding efficiency.

Compose also provides a Material Design component and theme implementation, as well as a concise animation API to make your application more dynamic and enjoyable.

2. Official advertising overview

Google, after all, has been holding back for two years. Compose is Google’s new declarative interface toolkit for Android. For example, Compose is used for creating a UI control and binding it to data. For example, Compose is used for creating a UI control and binding it to data.

Google is taking into account that the vast majority of what apps present today is not static data, but more real-time updates. But the existing XML interface, update is more complicated and tedious, easy to appear synchronization error. In addition, the complexity of software maintenance will increase with the number of views that need to be updated. In order to solve this problem, Google wants to completely abandon the original solution of writing views in XML and redevelop the complete solution of Compose.

Compose first generates the entire screen, and then only makes the necessary changes. It converts State into a UI and intelligently skips controls whose data has not changed and regenerates controls that have changed, a process known as recomposition. In addition, the Compose layout model does not allow multiple measurements, and a maximum of two measurements can be taken to calculate the dimensions of each component.

3. Environment construction

The IDE version is required. You need to download the latest version of Android Studio — Android Studio Arctic Fox, currently version 3.1 2020. This version has the ability to select the Compose template in the New Project, and features such as an instant preview of the Compose interface.

In general, with this kind of new technology, we will first practice non-core functions in the main project, and then slowly explore the holes, and then consider the old engineering code refactoring in a new way. Therefore, Compose can also be added to existing projects for use.

3.1 Configuring Kotlin and Gradle

You need to ensure that Kotlin version 1.5.10 and above is used in your project.

You also need to set your app’s minimum API level to 21 or higher, i.e., Android version 5.0 or higher. In addition, you need to enable Jetpack Compose in your Gradle file in your app directory and set the version of the Kotlin plugin.

android { defaultConfig { ... BuildFeatures {// Enables Jetpack Compose for this module Compose true // Enable Compose }... // Set both the Java and Kotlin compilers to target Java 8. compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 TargetCompatibility javchoc.version_1_8} kotlinOptions {jvmTarget = "1.8"} composeOptions {// Compiler plug-in version Settings KotlinCompilerExtensionVersion '1.0.0 - rc02'}}Copy the code

3.2 Adding Toolkit Dependencies

The following dependencies need to be added to the official document:

Dependencies {implementation 'androidx.com pose. The UI: UI: 1.0.0 - rc02' / / Tooling support (Previews, ) implementation 'androidx.compose. UI :ui-tooling:1.0.0-rc02' // Foundation (Border, Background, Box, Image, Scroll, shapes, animations, Etc.) implementation 'androidx.com pose. Foundation, foundation: 1.0.0 - rc02' / / Material Design implementation 'androidx.com pose. Material: material: 1.0.0 - rc02' / / material design ICONS implementation 'androidx.com pose. Material: material - the ICONS - the core: 1.0.0 - rc02' implementation 'androidx.com pose. Material: material - the ICONS - extended: 1.0.0 - rc02' / / Integration with activities implementation 'androidx. Activity: activity - compose: 1.3.0 - rc02' / / Integration with ViewModels implementation 'androidx. Lifecycle: lifecycle - viewmodel - compose: 1.0.0 - alpha07' / / Integration with observables implementation 'androidx.com pose. The runtime: the runtime - livedata: 1.0.0 - rc02' implementation 'androidx.com pose. The runtime: the runtime - rxjava2:1.0.0 - rc02' / / UI Tests androidTestImplementation 'androidx.com pose. The UI: UI - test - junit 4:1.0.0 - rc02'}Copy the code

There is no need to add Integration with Activities, ViewModels, and Observables if you just want to get started and see the effects.

4. Get started

The Compose core content is a Composable function that, as its English name suggests, breaks down the UI into Composable functions for easy maintenance and reuse. However, a composable function can only be called within the scope of other composable functions. To make a function Composable, simply add the @Composable annotation above the function. Think of the @composable annotation function as a View.

The @composable annotation tells the Compose compiler that this function is intended to transform data into an interface. And the Compose functions that generate the interface don’t need to return anything, because they describe the desired screen state, not the components that build the interface.

For example, Compose supports previewing Composable functions in the IDE. You simply add a @preview annotation to the Composable function. The constraint is that the @preview annotation can only be used for a function with no parameters, so if you want to Preview, Make sure the function you preview takes no arguments, or wrap it in a function that takes no arguments:

// code 1 @Composable fun Greeting(name: String) { Text(text = "Hello $name!" ) } @Preview @Composable fun WrapperView() { Greeting("hahahaha") }Copy the code

This way, you can see the preview in the IDE, without even an execution entry! Compose’s Composable function is composed of a Composable function in the setContent method:

// code 2 class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState) setContent {// Set the display content, equivalent to setContentView Greeting("Hello World!") )}}}Copy the code

4.1 Preliminary study on Compose layout

If you’ve written a Flutter, you’ll notice that the layout of Compose is similar to that of the Flutter. Column arranges elements from top to bottom, similar to the oritation of a LinearLayout layout, which is set to vertical. Row simply aligns elements from left to right, similar to the LinearLayout layout’s Oritation setting to Horizonal. And then there’s the Box stack layout, which is similar to the FrameLayout layout, which doesn’t expand anymore. Here is a simple example of a Column layout. The code looks like the image below:

// code 3@composable Fun NewStory() {Column(// many objects have this Modifier property. This property is very important, Image(painter = painterResource(id = r.drawable.header); ContentDescription = null) Text(" nice day ") Text(Text = "zhengzhou ") Text(Text = "July 2021")}} contentDescription = null) Text(" nice day ") Text(Text =" Zhengzhou ") Text(Text = "July 2021")}}Copy the code

Here’s the contentDescription property. The official teaching document reads:

Note: You also need to provide a contentDescription for the image. The description is used for accessibility. However, in a case like this where the image is purely decorative, it’s appropriate to set the description to null, as we do here.

We need to provide a contentDescription property for the image. This property is used for accessibility (=. =)? . However, if the image is purely decorative, it can also be set to null, as we did here.

Meng forced to face. Then go to the source code to see what this is in the end?

*@param contentDescription text used by accessibility services to describe what this image

*represents. This should always be provided unless this image is used for decorative purposes, *and does not represent a meaningful action that a user can take. This text should be *localized, such as by using [androidx.compose.ui.res.stringResource] or similar

This property is used by the accessibility service to describe what the image represents. The information for this attribute should be provided unless the diagram is used for decorative purposes only or does not represent an action of special significance to the user. In addition, the information text for the attribute should be stored in a local resource, such as a string in the res directory or somewhere similar.

Er… Still a little meng, went to the Internet to see the ImageView contentDescription property, seems to be for the convenience of the visually impaired people set. Anyway, the vast majority of cases can be ignored, if there is a practical use, welcome to exchange discussion.

In addition, the layout of Compose is very flexible, remember in the LinearLayout layout you can set weight to control the filling of the parent layout? For example, “Compose.

// code 4 @Composable fun MyScreenContent(names: List<String> = listOf("Android","there")) {Column(modifier = modifier.fillmaxHeight ()) {// similar to match_parent The Column (modifier = modifier. Weight (1 f)) {/ / layout for the height of the remaining space filled father (name names) in {Text (Text = name) Divider (color = }} Button(onClick = {}) {Text(Text = "this is the second Button")}}Copy the code

For this layout, you can place a Button at the bottom of the parent layout, and the remaining space of the parent layout will be filled by the Column layout on the inner layer.

Of course, Compose can easily follow Material Design principles because you can wrap a MaterialTheme {} directly around any Composable function, which makes use of the MaterialTheme properties. This includes font styles, color values, and so on. The code here is relatively simple, so I won’t repeat it here. Example code: gitee.com/xiuzhizhu/C…

4.2 Compose builds container functions

Compose supports building a container function, which is similar to a Theme. You can put some basic Settings in a container function, and the Composable function that is placed in the container function will be drawn and rendered based on the Settings. A simple example is chestnuts:

// code 5 // Declare a container function @composable Fun MyApp(content: @Composable () -> Unit) { MaterialTheme() { Surface(color = Color.Yellow, // Use MyApp {Text(Text = "modifier ")} // Use MyApp {Text(Text =" modifier ")} // Use MyApp {Text(Text = "modifier ")}Copy the code

All Composable functions placed in the MyApp container carry the properties set in the container functions. This improves code reusability and readability.

4.3 Preliminary study on Compose state

The core of Compose is the response to a change in the state state. Compose can display data on the UI by calling the Composable function, and it also provides a tool to observe changes in the data and automatically call back to display the UI, a process officially known as reorganization, as described above. You can think of it as updating the UI.

Inside the Composable function, we can use the mutableStateOf method to add a mutable state. To avoid having a different state each time a reorganization occurs, remember this mutable state.

// Code 6@composable Fun Counter() {val count = remember {mutableStateOf(0)} Count. Value ++}) {Text(Text = "${count. Value} times!" )}}Copy the code

This updates the number of clicks each time you click the Button.

4.4 Preliminary study of Compose list

The use of list layout is relatively high frequency, like ListView and RecyclerView are familiar with the View control used to display lists. LazyColumn would be the RecyclerView in Compose, which displays a long list of slides. It provides the Items API for displaying simple list layouts.

// code 7 @Composable fun NameList(names: List<String>, modifier: Modifier = Modifier) { LazyColumn(modifier = modifier) { items(items = names) { name -> Greeting(name = name) Divider(color = color.black) // Divider class objects}}}Copy the code

LazyColumn, however, does not cache the layout of a list like RecyclerView. Instead, it renders a new list View when scrolling through it. There is no recycling mechanism, but renders a Composable UI component more efficiently than instantiating an Android View.

4.5 Compose A custom theme

Compose has its own Theme, such as the MaterialTheme, wrapped around the Theme to render the properties set by the Theme. It is also possible to separate out some of the properties of these themes, such as fonts. Then you can use the various font styles set under the theme, as well as the color values:

// code 8 @Composable fun Greeting(name: String) {val greetingTypography = MaterialTheme. Typography // Get the MaterialTheme font style val greetingColors = MaterialTheme. Colors / / obtain MaterialTheme color value Text (Text = "Hello $name," color = greetingColors. OnBackground, // Use the onBackground color value of the MaterialTheme style = greetingTypography. Body2)}Copy the code

You can also call the copy method to copy the style of a theme and then override some of your own style properties:

// code 9
@Composable
fun Greeting(name: String) {
    val customStyle = MaterialTheme.typography.h5.copy(color = Color.Green)
    Text(text = "Hello $name",
        style = customStyle)
}
Copy the code

How to customize a Theme? It’s pretty simple. Here’s an example:

// code 10 // Composable functions wrapped in this method will be set to CustomTheme @composable fun CustomTheme(darkTheme: Boolean = isSystemInDarkTheme(), // Default to set to dark mode based on the system content: @composable () -> Unit {val colors = if (darkTheme) {DarkColors} else {LightColors} // MaterialTheme(colors = colors) {// Pass the set color value to content()}} private val DarkColors = DarkColors (// pass the color value in dark mode primary = Red300, primaryVariant = Red700, onPrimary = Color.Black, secondary = Red300, onSecondary = Color.Black, Error = Red200) private val LightColors = LightColors (primary = Red700, primaryVariant = Red900, onPrimary = Color.White, secondary = Red700, secondaryVariant = Red900, onSecondary = Color.White, error = Red800 )Copy the code

Is it easy? Yes, it’s that easy to customize a theme in Compose.

5. Programming ideas

Let’s talk about the programming idea for Compose in the official documentation. It uses a declarative interface model, which works by generating the entire screen from the start and then executing only the necessary changes. Reorganization is the process of updating the Composable function by calling it again with new data. Of course, the reorganization process only calls functions or lambdas that may have changed and skips the rest, so Compose can be reorganized efficiently.

It is recommended that you do not rely on the incidental effects of executing the Composable function when updating, as the reorganization of the function may be skipped. Side effects refer to any changes to the remaining visible parts of the application. Dangerous side effects include 1) writing the properties of the shared object (this should be in case some other logic is reading the properties of the shared object to update the UI, etc., making UI changes inaccurate). ; 2) Update observables in ViewModel (same principle as 1)); 3) Update SharedPreference. (not very understand, may in the future after real use will have more experience ~ welcome to discuss together)

The Composable function may be re-executed as frequently as each frame, for example when rendering an animation. The Composable function should execute quickly to avoid stalling during playback of the animation. If you need to perform a time-consuming operation, such as reading data from SharedPreference, it is recommended to process it in the back-end coroutine and then pass the current value using a callback to trigger the update. A few more noteworthy Tips:

If a Composable function contains several Composable functions, the Composable functions can be executed in any order. Compose identifies which interface elements take precedence over other interface elements and draws them first.

Compose can optimize reorganization by running its Composable functions in parallel. As a result, Compose can leverage multiple cores and run the Composable function at a lower priority. Thus, the Composable function might be executed in a background thread pool. When a Composable function is called, the call may occur in a different thread than the one that called it.

Compose will try to recompose only the parts that need to be updated, and each Composable function and lambda can recompose and update themselves. For example, if the Compose parameter is updated during a recombination, the current recombination is cancelled and the new parameter is used to start over.

It is recommended to write the Composable function at the top level for reuse.

For example, Compose is broad and profound. Many conceptual things are not well understood, and we need to practice them slowly to get real knowledge. Welcome to leave a message and learn from each other!

Ps. Simple Demo: gitee.com/xiuzhizhu/C… The official tutorial sites: developer. The android. Google. Cn/courses/pat…

reference

  1. Jetpack Compose 1.0 Modern Android toolkit for building native UIs
  2. Basics of Jetpack Compose
  3. Compose programming idea

Tail: This is the first article in the Compose series of notes. I believe that attentive students have also found that this note is recorded and learned according to the learning route on the official tutorial website. In the process of learning, encountered do not understand the place will also look up a lot of information to supplement, like, welcome to share forwarding and attention ~