SOLFIND
Web Lens
Portal home

UI layer (Views) | Android Developers

https://developer.android.com/topic/architecture/views/ui-layer • 101 KB fetched
Open original page


UI layer (Views) | Android Developers

Skip to main content

/

*
English

*
Deutsch

*
Español – América Latina

*
Français

*
Indonesia

*
Italiano

*
Polski

*
Português – Brasil

*
Tiếng Việt

*
Türkçe

*
Русский

*
עברית

*
العربيّة

*
فارسی

*
हिंदी

*
বাংলা

*
ภาษาไทย

*
中文 – 简体

*
中文 – 繁體

*
日本語

*
한국어

Android Studio

Sign in

Home

Guides

*

Home

*

Guides

*

Android Studio

*
Architecture for Views

* Recommendations for Android architecture

* About view binding

* Migrate from Kotlin synthetics to view binding

*
Data binding library

* About data binding

* Get started

* Layouts and binding expressions

* Work with observable data objects

* Generated binding classes

* Binding adapters

* Bind layout views to Architecture Components

* Two-way data binding

*
Lifecycle for Views

* Handling lifecycles with lifecycle-aware components

* Save UI states

* ViewModel overview

* Create ViewModels with dependencies

* ViewModel Scoping APIs

* Saved State module for ViewModel

* ViewModel APIs cheat sheet

* LiveData

* Use Kotlin coroutines with lifecycle-aware components

*
Paging for Views

* Page from network and database

* Transform data streams

* Manage and present loading states

* Test your Paging implementation

* Load and display paged data

* Migrate to Paging 3

* About Paging 2

* Display paged lists

* Load paged data

*
Dependency injection for Views

* Dependency injection with Hilt

* Manual dependency injection

* Hilt testing guide

*
App entry points for Views

* The activity lifecycle

*
App resources for Views

* App resources overview

* Handle configuration changes

* Localize your app

* Complex XML resources

* Drawable

* Layout

* Animation

* String resources

* Color state list

* Menu

* Font

* Style

* More types

*
UI layer for Views

* UI layer

* UI events

* UI State production

*

Android Developers

*

Develop

*

Core areas

*

UI

*

Views

*

Guides

UI layer (Views)

Stay organized with collections

Save and categorize content based on your preferences.

Concepts and Jetpack Compose implementation arrow_forward

The role of the UI is to display the application data on the screen and also to
serve as the primary point of user interaction. Whenever the data changes,
either due to user interaction (like pressing a button) or external input (like
a network response), the UI should update to reflect those changes.
Effectively, the UI is a visual representation of the application state as
retrieved from the data layer.

However, the application data you get from the data layer is usually in a
different format than the information you need to display. For example, you
might only need part of the data for the UI, or you might need to merge two
different data sources to present information that is relevant to the user.
Regardless of the logic you apply, you need to pass the UI all the information
it needs to render fully. The UI layer is the pipeline that converts
application data changes to a form that the UI can present and then displays
it.

Expose UI state

After you define your UI state and determine how you will manage the production
of that state, the next step is to present the produced state to the UI. Because
you're using UDF to manage the production of state, you can consider the
produced state to be a stream—in other words, multiple versions of the state
will be produced over time. As a result, you should expose the UI state in an
observable data holder like LiveData or StateFlow . The reason for this is so
that the UI can react to any changes made in the state without having to
manually pull data directly from the ViewModel. These types also have the
benefit of always having the latest version of the UI state cached, which is
useful for quick state restoration after configuration changes.

class NewsViewModel (...) : ViewModel () {

val uiState : StateFlow<NewsUiState> = …
}

A common way of creating a stream of UiState is by exposing a backing mutable
stream as an immutable stream from the ViewModel—for example, exposing a
MutableStateFlow<UiState> as a StateFlow<UiState> .

class NewsViewModel (...) : ViewModel () {

private val _uiState = MutableStateFlow ( NewsUiState ())
val uiState : StateFlow<NewsUiState> = _uiState . asStateFlow ()

...

}

The ViewModel can then expose methods that internally mutate the state,
publishing updates for the UI to consume. Take, for example, the case where an
asynchronous action needs to be performed; a coroutine can be launched using the
viewModelScope , and
the mutable state can be updated upon completion.

class NewsViewModel (
private val repository : NewsRepository ,
...
) : ViewModel () {

private val _uiState = MutableStateFlow ( NewsUiState ())
val uiState : StateFlow<NewsUiState> = _uiState . asStateFlow ()

private var fetchJob : Job? = null

fun fetchArticles ( category : String ) {
fetchJob ?. cancel ()
fetchJob = viewModelScope . launch {
try {
val newsItems = repository . newsItemsForCategory ( category )
_uiState . update {
it . copy ( newsItems = newsItems )
}
} catch ( ioe : IOException ) {
// Handle the error and notify the UI when appropriate.
_uiState . update {
val messages = getMessagesFromThrowable ( ioe )
it . copy ( userMessages = messages )
}
}
}
}
}

Consume UI state

When consuming observable data holders in the UI, make sure you take the
lifecycle of the UI into consideration. This is important because the UI
shouldn't be observing the UI state when the view isn't being displayed to the
user. To learn more about this topic, see this blog
post .
When using LiveData , the LifecycleOwner implicitly takes care of lifecycle
concerns. When using flows, it's best to handle this with the appropriate
coroutine scope and the repeatOnLifecycle API:

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
}
}
}
}
}

Note: The specific StateFlow objects used in this example don't stop
performing work when they have no active collectors, but when you're working
with flows you might not know how they're implemented. Using lifecycle-aware
flow collection lets you make these kinds of changes to the ViewModel flows
later without revisiting downstream collector code.
Show in-progress operations

A simple way to represent loading states in a UiState class is with a
boolean field:

data class NewsUiState (
val isFetchingArticles : Boolean = false ,
...
)

This flag's value represents the presence or absence of a progress bar in the
UI.

class NewsActivity : AppCompatActivity () {

private val viewModel : NewsViewModel by viewModels ()

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

lifecycleScope . launch {
repeatOnLifecycle ( Lifecycle . State . STARTED ) {
// Bind the visibility of the progressBar to the state
// of isFetchingArticles.
viewModel . uiState
. map { it . isFetchingArticles }
. distinctUntilChanged ()
. collect { progressBar . isVisible = it }
}
}
}
}

Animations

In order to provide fluid and smooth top-level navigation transitions, you might
want to wait for the second screen to load data before starting the animation.
The Android view framework provides hooks to delay transitions between fragment
destinations with the
postponeEnterTransition()
and
startPostponedEnterTransition()
APIs. These APIs provide a way to ensure that the UI elements on the second
screen (typically an image fetched from the network) are ready to be displayed
before the UI animates the transition to that screen.

Recommended for you

* Note: link text is displayed when JavaScript is off

* UI State production

* State holders and UI State {:#mad-arch}

* Guide to app architecture

Content and code samples on this page are subject to the licenses described in the Content License . Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2026-05-05 UTC.

*

X

Follow @AndroidDev on X

*

YouTube

Check out Android Developers on YouTube

*

LinkedIn

Connect with the Android Developers community on LinkedIn

*
More Android

*

Android

*

Android for Enterprise

*

Security

*

Source

*

News

*

Blog

*

Podcasts

*
Discover

*

Gaming

*

Machine Learning

*

Health & Fitness

*

Camera & Media

*

Privacy

*

5G

*
Android Devices

*

Large screens

*

Wear OS

*

ChromeOS devices

*

Android for cars

*

Android TV

*
Releases

*

Android 17

*

Android 16

*

Android 15

*

Android 14

*

Android 13

*

Android 12

*

Android 11

*
Documentation and Downloads

*

Android Studio guide

*

Developers guides

*

API reference

*

Download Studio

*

Android NDK

*
Support

*

Report platform bug

*

Report documentation bug

*

Google Play support

*

Join research studies

*

Android

*

Chrome

*

Firebase

*

Google Cloud Platform

*

All products

*

Privacy

*

License

*

Brand guidelines

*

Manage cookies

*

Get news and tips by email

Subscribe

*
English

*
Deutsch

*
Español – América Latina

*
Français

*
Indonesia

*
Italiano

*
Polski

*
Português – Brasil

*
Tiếng Việt

*
Türkçe

*
Русский

*
עברית

*
العربيّة

*
فارسی

*
हिंदी

*
বাংলা

*
ภาษาไทย

*
中文 – 简体

*
中文 – 繁體

*
日本語

*
한국어

Links found on this page

  1. Skip to main content [direct]
  2. Android Studio [direct]
  3. Home [direct]
  4. Guides [direct]
  5. About view binding [direct]
  6. Migrate from Kotlin synthetics to view binding [direct]
  7. About data binding [direct]
  8. Get started [direct]
  9. Layouts and binding expressions [direct]
  10. Work with observable data objects [direct]
  11. Generated binding classes [direct]
  12. Binding adapters [direct]
  13. Bind layout views to Architecture Components [direct]
  14. Two-way data binding [direct]
  15. Handling lifecycles with lifecycle-aware components [direct]
  16. Save UI states [direct]
  17. ViewModel overview [direct]
  18. Create ViewModels with dependencies [direct]
  19. ViewModel Scoping APIs [direct]
  20. Saved State module for ViewModel [direct]
  21. ViewModel APIs cheat sheet [direct]
  22. LiveData [direct]
  23. Use Kotlin coroutines with lifecycle-aware components [direct]
  24. Page from network and database [direct]
  25. Transform data streams [direct]
  26. Manage and present loading states [direct]
  27. Test your Paging implementation [direct]
  28. Load and display paged data [direct]
  29. Migrate to Paging 3 [direct]
  30. About Paging 2 [direct]
  31. Display paged lists [direct]
  32. Load paged data [direct]
  33. Dependency injection with Hilt [direct]
  34. Manual dependency injection [direct]
  35. Hilt testing guide [direct]
  36. The activity lifecycle [direct]
  37. App resources overview [direct]
  38. Handle configuration changes [direct]
  39. Localize your app [direct]
  40. Complex XML resources [direct]
  41. Drawable [direct]
  42. Layout [direct]
  43. Animation [direct]
  44. String resources [direct]
  45. Color state list [direct]
  46. Menu [direct]
  47. Font [direct]
  48. Style [direct]
  49. More types [direct]
  50. UI events [direct]
  51. UI State production [direct]
  52. Android Developers [direct]
  53. Develop [direct]
  54. Core areas [direct]
  55. UI [direct]
  56. Concepts and Jetpack Compose implementation arrow_forward [direct]
  57. viewModelScope [direct]
  58. this blog post [direct]
  59. postponeEnterTransition() [direct]
  60. UI State production [direct]
  61. State holders and UI State {:#mad-arch} [direct]
  62. Guide to app architecture [direct]
  63. Content License [direct]
  64. X [direct]
  65. YouTube [direct]
  66. LinkedIn [direct]
  67. Android [direct]
  68. Android for Enterprise [direct]
  69. Security [direct]
  70. Source [direct]
  71. News [direct]
  72. Blog [direct]
  73. Podcasts [direct]
  74. Gaming [direct]
  75. Machine Learning [direct]
  76. Health & Fitness [direct]
  77. Camera & Media [direct]
  78. Privacy [direct]
  79. 5G [direct]
  80. Large screens [direct]