The Implementation of UI Layer in Android App Architecture

Kayvan Kaseb
Software Development
7 min readApr 20, 2022
The picture is provided by Unsplash

Essentially, software architecture serves as a blueprint for software development basis in order to increase the performance of systems and to diminish development costs as well. This means the structure of the software could make impacts on important decisions throughout the development process, and it could be considered as the evolution of the software in future. As a result, to find better patterns for building software in a fast and reliable way, enterprise software architecture always evolves with advanced architectural styles. In particular, it would be extremely important to define an architecture for Android apps because there have been a considerable growth in size in recent years. Nowadays, some guidelines and best-practices have been offered by Google to develop high-quality Android apps with effective architecture in practice. This essay will provide you with some main concepts and guidelines for implementing the UI layer in Android app architecture.

Introduction and Overview

Initially, even though there are a number of definitions of software, architecture could be defined as an abstraction of a system. Since architecture consists of structures, and also structures contain components and relations, it follows that an architecture comprises software components and how the components interact to each other. It serves as a blueprint for software development basis in order to increase the performance of systems and to diminish development costs as well. The structure of the software could make impacts on important decisions throughout the development process, and it could be considered as the evolution of the software in future. Therefore, to find better patterns for implementing software in a fast and reliable way, enterprise software architecture always evolves with new architectural styles. In particular, it would be extremely significant to define an architecture for Android apps because there have been a considerable growth in size in recent years. In other words, Android App architecture plays a vital role in the following issues: scaling the app, improving the app’s robustness, and making the app easier to test.

Recently, some guidelines and best-practices have been offered by Google to develop high-quality Android apps with effective architecture in practice. In short, Google has offered that each Android app should include two layers at least: First, the UI layer that demonstrates app data on the screen. Second, the data layer that includes the business logic of your app and exposes application data. Nevertheless, to ease and reuse the interactions between the UI and data layers, you can be able to add an optional layer called the domain layer, which sits between the UI and data layers.

The picture is provided by Google documents

This article will discuss some main concepts and guidelines for implementing the UI layer in Android app architecture.

Defining the UI layer

Fundamentally, the main role of the UI layer or presentation layer is to show the application data on screen. In addition, it serves as the central point of user interaction. Typically, if the data changes in an Android app because of several reasons, such as pressing a button or receiving a network response, the UI should update and reflect those changes properly. The data layer could be the easiest layer to understand and the hardest one to work with at the same time because there are many challenges should be addressed appropriately, such as different lifecycles of UI components and state management.

Effectively, the UI is a visual representation of the application state as retrieved from the data layer.

Generally, the UI layer includes two issues: UI elements + UI state = UI

In other words, UI elements render the data on the screen. So, you can be able to create these elements via Views or Jetpack Compose functions. Jetpack Compose is Android’s powerful tool for implementing native UI in order to simplifies and accelerates UI development on Android. To understand the capabilities of Jetpack Compose fully, the Jetnews has been developed as a news reading app sample with Jetpack Compose. Also, state holders, like ViewModel classes can perform some tasks effectively as follows: holding data, exposing it to the UI, and managing logic.

The picture is provided by Google documents

As it was mentioned, the main role of the data layer is holding, handling, and providing access to the app data. Thus, the UI layer has to accomplish the following steps successfully:

1. Transforming App data to UI specific app data.

2. Updating UI elements to reflect UI specific data.

3. Processing user input events that lead to UI changes.

4. Repeating all the above steps as long as necessary.

One of the key points in this matter is that the UI state definition should be immutable because this can be useful for maintaining the focus of UI layer on main purpose: reading the state and updating its related UI elements. So, you should never modify the UI state in the UI directly unless the UI itself is the one and only source of its data due to dealing with inconsistencies and bugs.

State Managements with Unidirectional Data Flow (UDF)

Basically, an appropriate solution for state managements could play a prominent role for developing a reliable Android app because it can tackle the dynamic nature of changing in Android development. The classes that are responsible for the production of UI state and consist of the necessary logic for that task are called state holders. Moreover, UI events are actions that should be managed in the UI layer, either by the UI or by the ViewModel. The most common kind of events are user events, which are produced by interacting with the Android app. This means the ViewModel is in charge of managing the business logic of a special user event. Essentially, the business logic can be classified into two main category in this area: First, in terms of what to do with state changes, you should handle this kind of business logic in the domain and data layers. Second, according to how to display state changes, the UI layer should manage this UI behavior logic, such as implementing navigation logic or showing messages to the user.

Another key points is that if your UI logic contains some types like Context, you should put it in the UI elements, not in the ViewModel. However, in some cases because of complexity of UI, you can have an opportunity to create a simple class as a state holder for these types in order to follow separation of concerns as a guideline in your code.

The UDF mechanism, the picture is provided by Google documents

As a matter of fact, although there are many ways to represent the interaction between the UI and its state producer, a unidirectional data flow (UDF) could be a proper pattern to display this interaction. In this pattern, the state can flow down and the events can flow up. One of the main benefits of using this pattern is separating the source of state changes and place of consumption in practice. So, this leads to data consistency, testability, and maintainability.

Now, the question is that how to know the UI state has been changed? The answer is observable data.

Observer can be considered as a behavioral design pattern in various programming languages. It describes communication between objects: observable and observers. An observable is an object that notifies observers about the changes in its state. For instance, a news agency can notify channels when it receives news. Receiving news is what changes the state of the news agency, and it causes the channels to be notified.

Exposing and Consuming UI States

The UI state should be exposed in an observables data holder, like StateFlow or LiveData. The reason is that the UI can be able to react to any changes made in the state without having to pull data manually from the ViewModel in a direct way. Additionally, these observable data type have the latest version of the UI state cached, which is helpful for quick state restoration after configuration changes.

In Jetpack Compose apps, you can use Compose’s observable State APIs such as mutableStateOf or snapshotFlow for the exposure of UI state. Any type of observable data holder such as StateFlow or LiveData that you see in this guide can be easily consumed in Compose using the appropriate extensions.

StateFlow is a state-holder observable flow that emits the current and new state updates to its collectors.

Consuming UI state is performed with the terminal operator on the observable data type. For instance, if you use LiveData, this is the observe() method. Also, if you use the Kotlin flows, this is the collect() method. Most importantly, while observing and consuming UI state in the UI, you should not ignore the lifecycle of the UI. Oftentimes, state holders like ViewModels live much longer than the UIs that observe them. So, you should make sure that they are not observing UI state when they cannot be seen.

class NewsActivity : AppCompatActivity() {

private val viewModel: NewsViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
//...

lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Update UI elements
}
}
}
}
}

If you use LiveData, the LifecycleOwner can implicitly support lifecycle concerns. Eventually, if you use Kotlin flows, you can face this issue with the appropriate coroutine scope and the repeatOnLifecycle API.

In conclusion

Recently, some guidelines and best-practices have been suggested by Google to develop high-quality Android apps with effective architecture in practice. As a matter of fact, Google has offered that each Android app should contain two layers at least: First, the UI layer that demonstrates app data on the screen. Second, the data layer that includes the business logic of your app and exposes application data. This article discussed some main concepts and guidelines for implementing the UI layer in Android app architecture based on Google resources.

--

--

Kayvan Kaseb
Software Development

Senior Android Developer, Technical Writer, Researcher, Artist, Founder of PURE SOFTWARE YAZILIM LİMİTED ŞİRKETİ https://www.linkedin.com/in/kayvan-kaseb