Jetpack Compose: The Future of Android UI Jetpack Compose comes with all the functionality needed to build a rich and responsive application UI and features full interoperability with current Android views, making it easy for developers to implement in existing projects. Annika Hey Design Principal Atanas Atanasov Software Development Manager – Agile Frameworks Björn Stansvik Founder & Chief Executive Officer Daniela Nazim MentorMate Alumni Dimitar Dobrev MentorMate Alumni Craig Knighton Chief Operating Officer Eleonora Georgieva Global VP, Delivery George Dormishev System Administration Manager Ivaylo Kostadinov Director, Software Engineering - .NET Jamie Bolseth MentorMate Alumni Jay Miller President Jeni Kyuchukova Director, Quality Engineering Jessica Anderson VP of Finance and Administration Liz Spolyar Global Director, Continuation Engineering Nick Curran Technical Architect Nikolay Lyubchev Global Director, Talent Acquisition, MentorMate Stefan Tsvyatkov Director, Software Engineering - Mobile Stefan Tzanev Chief Financial Officer Vesselin Dobrev General Manager (Bulgaria) Sylvia Vassileva Software Development Manager - Spok Filip Gajtanovski Software Development Manager - Storyworks Krasimir K. Nikolov VP of Technology Katherine Kelly Director of Operations (USA) Carrie Siewert Strategic Account Manager Brady Swanson Global Director, Marketing Eve Poeschl MentorMate Alumni Ryan Peña MentorMate Alumni Vassil Vassilev Software Development Manager - .NET Pavel Petrov Director, Software Engineering - LAMP&FE Ivan Peev Senior Technology Manager Bob Reuss MentorMate Alumni Vera Kasapova QA Manager Greta Yamacheva QA Manager Robert Samuelsson General Manager (Sweden) Kyle Simmons Solutions Architect Robin Thomas Solutions Architect Nataliya Naydenova MentorMate Alumni Adam Malone Alexander Dimitrov Enterprise Architect Andrea Kates CEO, LaunchPad Central Andrew Eklund CEO, Ciceron Andrew Marinov Angel Nikolov MentorMate Alumni Anurag Shukla Aron Wolde MentorMate Alumni Ashley Goodridge Office Assistant Benjamin Gramlich MentorMate Alumni Chris Black MentorMate Alumni Christa Haeg MentorMate Alumni Colin Lee MentorMate Alumni Deyan Stoynov MentorMate Alumni Dimitar Danailov MentorMate Alumni Dobrinka Tabakova Doug Leatherman Emily Genco MentorMate Alumni Fanka Vassileva Gabriela Zagarova MentorMate Alumni Gary Conkright CEO, physIQ Gary Fingerhut Executive Director, Cleveland Clinic Innovations Gavin Finden MentorMate Alumni Georgi Graham Klang Hyusein Hyuseinov Senior Automation QA Ian Good Global VP, Operations Iva Jack Cosentino James Williams John Byrne Kaloyan Stoilkov MentorMate Alumni Kosta Hristov Krasimir Gatev Senior Android Developer Lazar Petrakiev Lyubomir Dobrev Senior .NET Developer Lubomir Velkov Marin Yotovski Mark Smith MentorMate Alumni Martin Dimitrov MentorMate Alumni Martin Kalyonski Mike Hagan MentorMate Alumni Nikolay Andonov Nikolay Arhangelov Riley Panko Guest Contributor Roger Ferguson MentorMate Alumni Ryan Sysko Chairman, WellDoc Ryan Blake MentorMate Alumnus Sarah Rockholt MentorMate Alumni Sean McDevitt CEO, Sensei Siyana Slavova Stanislas Walden MentorMate Alumni Stanislav Atanasov Stanislava Bogdanova MentorMate Alumni Stefanie Trimble MentorMate Alumnus Stephen Fluin Stoyan Stoyanov MentorMate Alumnus Tessa Cacek Staffing Manager Tom Clemens MentorMate Alumnus V8 JavaScript Engine Viktor Mitev Yolanda Petkova Marketing Design Lead Pete Anderson Lead Product Owner, Target Vasil Nonchev Java Software Development Manager Dilyana Totseva QA Manager Stanimir Nikolov Software Development Lead - iOS, MentorMate Rosen Kolev Technology Principal Dimitar Mihaylov MentorMate Alumni Nikola Genov Software Architect - .NET Neli Todorova Software Development Manager - LAMP Yavor Dimitrov MentorMate Alumni Georgi Karanedyalkov Software Development Lead - Android, MentorMate Denislav Ganchev Technology Principal Stefan Shopov QA Manager Konstantin Rusev Java Developer Borislav Dimitrov Senior Android Developer, MentorMate Tsvetelina Lazarova MentorMate Alumni Dimitar Gadzhev Developer Plamen Stoev Software Development Manager - Front-end Jake Nelsen Senior Experience Designer Zlati Pehlivanov Senior Software Engineer II Kate Tolmie Senior Experience Designer Martin Angelov Director, Software Engineering - LAMP&FE, MentorMate Dimitar Zhelev Senior .NET Developer Joel Swenson Content Manager Kiril Ivanov Quality Assurance Analyst Viktor Hristoskov Software Development Lead - iOS, MentorMate Violeta Nikolcheva Database Developer Biliana Kadakevlieva Senior Quality Assurance Analyst Chris McLeod Senior Solutions Consultant Antonii Georgiev Junior .NET Developer Alexander Rusev Front-End Developer Matt Erickson MentorMate Alumni Brian Buchkosky Global Director, PMO David Tran MentorMate Alumni Kristin Krueger MentorMate Alumni Magdalena Chervenkova Business Analyst Denny Royal Chief Design Officer Joe Bodell MentorMate Alumni Viktoria Chuchumisheva HR Manager Kalina Tekelieva Senior Content Marketing Artist Daniel Rankov MentorMate Alumni Alexander Alexandrov BA Lead MentorMate Clint Rowles VP, Business Development Nikola Donev SysOps & DevOps Lead Tseko Tsolov Frontend Developer Denislav Lefterov Automation QA Analyst Dilyana Kodjamanova MentorMate Alumni Emma Jorstad Project Manager, Lead Georgi Georgiev Software Development Lead - LAMP, MentorMate Martin Panayotov Senior iOS Developer, MentorMate John Blake Senior Account Manager Tyler Compton Solutions Architect Nikola Peevski Software Developer — Lamp & Front-End Aaron Whitney Director of Client Strategy Veliko Ivanov Senior Cloud Engineer Suzanne O’Brien Senior Project Manager Svetlin Stanchev Software Development Lead - Front-end, MentorMate Todor Todorov Senior Cloud Engineer Kate Stamatova Senior QA Analyst Frank Anselmo Global Director, Project Management Gyuner Zeki Solutions Architect Galin Stanchev QA Analyst Sarah Hoops Business Development Manager Brenden Diehl Business Development Manager Anna Krivova Software Development Lead - Front-end, MentorMate Ivelina Kavalova Senior Business Analyst, MentorMate Paul Sanders MentorMate Alumni Jim Cikanek Senior Client Strategist Samuil Yanovski Software Development Manager - Android, MentorMate Krasimir Gatev Senior Android Developer, MentorMate Kristina Goryalova Talent Acquisition Manager Elena Petrova HR Specialist Jay Matre Senior Business Architect, MentorMate Lilyana Dimitrova QA Specialist Josh Marquart Chief Strategy Officer Mario Gorki Senior Mobile Developer Simeon Zhekov Cloud Engineer Hristo Stoyanov Cloud & DevOps Lead Ben Wallace Enterprise Architect Boyan Stoyanov Data & Dota Specialist Petya Ivanova Director, Software Engineering - Java Sebastian Ortiz-Chamorro VP of Engineering, Latin America Consuelo Merino Director of Operations, MentorMate Carlos Rodríguez Data & Analytics Manager, MentorMate Joel Hernandez CTO, eLumen Introduction Jetpack Compose is a new modern, declarative UI toolkit developed by Google and used for building quick and efficient user interface components for Android applications. It leverages the power and expressiveness of the Kotlin language and is unbundled, similar to other Jetpack libraries, ensuring consistency across different API versions. It comes with all the functionality needed to build a rich and responsive application UI and features full interoperability with current Android views, making it easy for developers to implement in existing projects. But why choose Compose when Android already has robust UI creation tools using views, widgets, and XML? Due to Compose’s powerful declarative syntax and structure, developers can create rich UI many times faster than with the old toolset. Due to how state and data are handled in Compose, developers are less likely to make costly errors and introduce hard-to-find bugs in their codebase. UI and State With many imperative, object-oriented UI toolkits, the UI is initialized by instantiating a tree of widgets. This is often done by inflating an XML layout file. Each widget maintains its internal state and exposes getter and setter methods that allow the app logic to interact with the widget. In contrast to this, in Compose’s declarative approach, widgets are relatively stateless and do not expose setter or getter functions. Widgets are not exposed as objects. The composables are responsible for transforming the current application state into a UI every time the observable data updates. The concept where the UI is changed directly to reflect changes in the app’s state is not new and is embraced by many different modern development platforms. Some of these are also used for Android development, such as React and Flutter. The new Jetpack Compose toolkit is an evolution of this paradigm. At its core, it emits UI directly, smartly modifying only the views affected by the data change. In this way, the UI always reflects the current state of the app’s data and prevents issues caused by developers manually handling the synchronization task themselves. When using Compose, the information flow will be unilateral – it will only flow in one direction from the data state to the views. This means that architectures such as MVP with a two-way communication flow might be more challenging to integrate with Compose. Preferable architectures such as Google’s recommended MVVM can use LiveData and ViewModels to observe state changes and automatically emit new UI using Compose if needed. Getting Started The core building blocks of Jetpack Compose are the composable functions. These functions take some input and describe a part of the app’s UI, generating what’s shown on the screen. A composable function is created by adding the @Composable annotation to the function name. Similar to coroutines, composable functions can only be called from within the scope of other composable functions. Composable functions can accept parameters that allow the app logic to describe the UI. These parameters can also include LiveData objects which can be updated dynamically. Each time a parameter is changed, the composable function will be triggered again so that a new UI can be emitted to reflect the change. Composable functions emit UI hierarchy by calling other composable functions. In this example, the Text() function creates the text UI element. Composable functions don’t return anything. They describe the desired screen state and directly emit UI instead of constructing UI widgets. That is why they do not need to return anything. Composable functions can be previewed inside the Android Studio IDE by adding the @Preview annotation before @Composable. Currently, only functions without any parameters can be previewed in this way. Recomposition In the old imperative UI model, to change a widget, a setter must be called on the widget to change its internal state. In Compose, the composable function is automatically called again when there is a change in the data. This causes the function to be recomposed, and in turn, the widgets emitted by the function are redrawn, if necessary, with the new data. The Compose framework can intelligently recompose only the components that have changed. The process of calling your composable functions again when inputs change is called recomposition. When Compose recomposes based on new inputs, it smartly only calls the functions or lambdas in the code that might have changed and skips the rest. By skipping all functions or lambdas that don’t have changed parameters, Compose can recompose efficiently and greatly improve the performance of the UI. Composable functions might be re-executed as often as every frame, such as when an animation is being rendered. It is very important to keep these functions fast to avoid jank during animations and view creation. Suppose expensive operations need to be executed, such as reading from shared preferences or making complex calculations. In that case, these should be done in a background coroutine and their values passed to the composable function as a parameter. Ignoring these best practices could lead to unresponsive UI and stutter, especially when scrolling lists and animating components. Things to be aware of when using Compose: Composable functions can execute in any order. Composable functions can execute in parallel. Recomposition skips as many composable functions and lambdas as possible. Recomposition is optimistic and may be canceled. A composable function might be run quite frequently, as often as every frame of an animation. Layouts and UI Hierarchy At their core, composable functions are used to emit UI elements. A single function can emit several UI elements. However, developers should guide how these should be arranged to achieve the desired outcome. Special layout functions can be used, like Column that places items vertically on the screen, or Row that places them horizontally. Both Column and Row support configuring the alignment of the elements they contain. To display elements one on top of the other, developers can use the Box function. These fundamental building blocks are often enough to create most layout configurations, but they can also be combined to form more elaborate structures if required. In contrast to Android views, where developers need to avoid nested layouts for performance reasons, Compose handles nested layouts very efficiently, making them a great way to design a complicated UI. To customize, decorate, and augment composables, the Compose toolkit uses modifiers. These are standard Kotlin objects which can be created by calling one of the Modifier class functions. These functions can be chained together to set multiple properties at once. In this case, the order of chaining is important, as each function makes changes to the modifier object returned by the previous one, so that the sequence will affect the final result. Modifiers enable developers to customize a large set of things, including: Change the composable’s size, layout, behavior, and appearance. Add information, like accessibility labels. Process user input. Add high-level interactions, like making an element clickable, scrollable, draggable, etc. Lists The list component is a fundamental building block of every Android app. Its main feature is the ability to render only the currently visible elements on the screen, thus improving the list’s performance and responsiveness. In the past, this was achieved by the Android RecyclerView which required cumbersome adapter classes to be created and maintained. Creating list headers and footers was also a pain, especially if these had custom behavior such as sticky headers. With Jetpack Compose this functionality can be achieved with just a few lines of code using the new lazy composable functions, such as the LazyColumn() function. These are different from other Compose layout functions, as they have their own DSL (domain specific language) used to achieve the desired behavior. The main building block used by the Compose list is the items() function used to describe and lay out the items that will be displayed on the screen. This can be done by supplying the function with a list of objects that will emit the UI for a given item in the list. Just like with RecyclerView, lists created with Compose can be arranged in different layout patterns. LazyColumn is used for vertical lists, while horizontal lists can be created with LazyRow. To create more complex grid patterns, LazyVerticalGrid can be used. The app will need to react and listen to scroll position and item layout changes in some cases. The lazy components handle this use-case by employing the rememberLazyListState() function that provides a reference that tracks the list’s current state. While it is a best practice to supply all the needed data up front as parameters to the Compose function, there will be times where it will be required to execute code asynchronously inside the function itself. The recommended way to do this is with the new coroutines introduced in Kotlin. To use coroutines inside a Compose function, a coroutine scope has to be acquired first. This is achieved by calling the special rememberCouroutineScope() function. After that, we can easily launch the coroutine by calling scope.launch(). Conclusion The Jetpack Compose toolkit is being developed rapidly by Google and will soon become the preferred way of creating UI for Android applications. It will be beneficial to many developers to get acquainted with it as early as possible. This new powerful tool brings many improvements to the UI creation process, allowing users to achieve more with less code and produce a highly maintainable and less error-prone codebase. Jetpack Compose does not only bring benefits, though. It presents additional challenges that have to be overcome by developers. They will have to learn and adapt to a completely new way of building the user interface of their apps while being more mindful of the performance and structure of their UI code. A key factor to successfully implementing Compose will be obtaining a fundamental understanding of how recomposition and state work inside the toolkit. These good practices will help developers achieve better optimization and performance and improve their app’s structure and data flow. Tags MobileDevelopment Share Share on Facebook Share on LinkedIn Share on Twitter Share Share on Facebook Share on LinkedIn Share on Twitter Sign up for our monthly newsletter. Sign up for our monthly newsletter.