This page presents several [Architecture](https://developer.android.com/topic/architecture) best practices and recommendations.
Adopt them to improve your app's quality, robustness, and scalability. They also
make it easier to maintain and test your app.
| **Note:** You should treat the recommendations in the document as recommendations and not strict requirements. Adapt them to your app as needed.

The best practices below are grouped by topic. Each has a priority that reflects
how strongly the team recommends it. The list of priorities is as follows:

- **Strongly recommended:** You should implement this practice unless it clashes fundamentally with your approach.
- **Recommended:** This practice is likely to improve your app.
- **Optional:** This practice can improve your app in certain circumstances.

| **Note:** In order to understand these recommendations, you should be familiar with the [Architecture guidance](https://developer.android.com/topic/architecture).

## Layered architecture

Our recommended [layered architecture](https://developer.android.com/topic/architecture?gclid=CjwKCAjw6raYBhB7EiwABge5Klm_5PN8nJF0Jrb_ymrPP0JAEsbmemmGv_nsn0nBQKQtQMCBuvjehRoC7qcQAvD_BwE&gclsrc=aw.ds#recommended-app-arch) favors separation of concerns. It
drives UI from data models, complies with the single source of truth principle,
and follows [unidirectional data flow](https://developer.android.com/topic/architecture?gclid=CjwKCAjw6raYBhB7EiwABge5Klm_5PN8nJF0Jrb_ymrPP0JAEsbmemmGv_nsn0nBQKQtQMCBuvjehRoC7qcQAvD_BwE&gclsrc=aw.ds#unidirectional-data-flow) principles. Here are some best
practices for layered architecture:

| Recommendation | Description |
|---|---|
| Use a clearly defined [data layer](https://developer.android.com/jetpack/guide/data-layer). **Strongly recommended** | The [data layer](https://developer.android.com/jetpack/guide/data-layer) exposes application data to the rest of the app and contains the vast majority of business logic of your app. - You should create [repositories](https://developer.android.com/topic/architecture/data-layer#architecture) even if they just contain a single data source. - In small apps, you can choose to place data layer types in a `data` package or module. |
| Use a clearly defined [UI layer](https://developer.android.com/jetpack/guide/ui-layer). **Strongly recommended** | The [UI layer](https://developer.android.com/jetpack/guide/ui-layer) displays the application data on the screen and serves as the primary point of user interaction. - In small apps, you can choose to place data layer types in a `ui` package or module. [More UI layer best practices here](https://developer.android.com/topic/architecture/recommendations#ui-layer). |
| The [data layer](https://developer.android.com/jetpack/guide/data-layer) should expose application data using a repository. **Strongly recommended** | Components in the UI layer such as composables, activities, or ViewModels shouldn't interact directly with a data source. Examples of data sources are: - Databases, DataStore, SharedPreferences, Firebase APIs. - GPS location providers. - Bluetooth data providers. - Network connectivity status provider. |
| Use [coroutines and flows](https://developer.android.com/kotlin/coroutines?gclid=CjwKCAjwhNWZBhB_EiwAPzlhNtReVIBfrUFBUt6SqZz3YLezP9YEiGuBube4YSTrOF-0ovxzpNGNaRoCiYsQAvD_BwE&gclsrc=aw.ds). **Strongly recommended** | Use [coroutines and flows](https://developer.android.com/kotlin/coroutines?gclid=CjwKCAjwhNWZBhB_EiwAPzlhNtReVIBfrUFBUt6SqZz3YLezP9YEiGuBube4YSTrOF-0ovxzpNGNaRoCiYsQAvD_BwE&gclsrc=aw.ds) to communicate between layers. [More coroutines best practices here](https://developer.android.com/kotlin/coroutines/coroutines-best-practices). |
| Use a [domain layer](https://developer.android.com/jetpack/guide/domain-layer). **Recommended in big apps** | Use a [domain layer](https://developer.android.com/jetpack/guide/domain-layer), use cases, if you need to reuse business logic that interacts with the data layer across multiple ViewModels, or you want to simplify the business logic complexity of a particular ViewModel |

## UI layer

The role of the [UI layer](https://developer.android.com/topic/architecture/ui-layer) is to display the application data on the screen
and serve as the primary point of user interaction. Here are some best practices
for the UI layer:

| Recommendation | Description |
|---|---|
| Follow [Unidirectional Data Flow (UDF)](https://developer.android.com/jetpack/compose/architecture#udf). **Strongly recommended** | Follow [Unidirectional Data Flow (UDF)](https://developer.android.com/jetpack/compose/architecture#udf) principles, where ViewModels expose UI state using the observer pattern and receive actions from the UI through method calls. |
| Use [AAC ViewModels](https://developer.android.com/topic/libraries/architecture/viewmodel) if their benefits apply to your app. **Strongly recommended** | Use [AAC ViewModels](https://developer.android.com/topic/libraries/architecture/viewmodel) to [handle business logic](https://developer.android.com/jetpack/guide/ui-layer#logic-types), and fetch application data to expose UI state to the UI (Compose or Android Views). See more [ViewModel best practices here.](https://developer.android.com/topic/architecture/recommendations#viewmodel) See the [benefits of ViewModels here.](https://developer.android.com/topic/architecture/ui-layer/stateholders#viewmodel-as) |
| Use lifecycle-aware UI state collection. **Strongly recommended** | Collect UI state from the UI using the appropriate lifecycle-aware coroutine builder: [`repeatOnLifecycle`](https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#(androidx.lifecycle.Lifecycle).repeatOnLifecycle(androidx.lifecycle.Lifecycle.State,kotlin.coroutines.SuspendFunction1)) in the View system and [`collectAsStateWithLifecycle`](https://developer.android.com/reference/kotlin/androidx/lifecycle/compose/package-summary#(kotlinx.coroutines.flow.StateFlow).collectAsStateWithLifecycle(androidx.lifecycle.LifecycleOwner,androidx.lifecycle.Lifecycle.State,kotlin.coroutines.CoroutineContext)) in Jetpack Compose. Read more about[`repeatOnLifecycle`](https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda). Read more about about[`collectAsStateWithLifecycle`](https://medium.com/androiddevelopers/consuming-flows-safely-in-jetpack-compose-cde014d0d5a3). |
| Do not send events from the ViewModel to the UI. **Strongly recommended** | Process the event immediately in the ViewModel and cause a state update with the result of handling the event. More about [UI events here](https://developer.android.com/topic/architecture/ui-layer/events#handle-viewmodel-events). |
| Use a single-activity application. **Recommended** | Use [Navigation Fragments](https://developer.android.com/guide/navigation) or [Navigation Compose](https://developer.android.com/jetpack/compose/navigation) to navigate between screens and deep link to your app if your app has more than one screen. |
| Use [Jetpack Compose](https://developer.android.com/jetpack/compose). **Recommended** | Use [Jetpack Compose](https://developer.android.com/jetpack/compose) to build new apps for phones, tablets and foldables and Wear OS. |

The following snippet outlines how to collect the UI state in a lifecycle-aware
manner:  

### Views

    class MyFragment : Fragment() {

        private val viewModel: MyViewModel by viewModel()

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            viewLifecycleOwner.lifecycleScope.launch {
                viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                    viewModel.uiState.collect {
                        // Process item
                    }
                }
            }
        }
    }

### Compose

    @Composable
    fun MyScreen(
        viewModel: MyViewModel = viewModel()
    ) {
        val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    }

## ViewModel

[ViewModels](https://developer.android.com/topic/architecture/ui-layer/stateholders#business-logic) are responsible for providing the UI state and access to the
data layer. Here are some best practices for ViewModels:

| Recommendation | Description |
|---|---|
| ViewModels should be agnostic of the Android lifecycle. **Strongly recommended** | ViewModels shouldn't hold a reference to any Lifecycle-related type. Don't pass `Activity, Fragment, Context` or `Resources` as a dependency. If something needs a `Context` in the ViewModel, you should strongly evaluate if that is in the right layer. |
| Use [coroutines and flows](https://developer.android.com/kotlin/coroutines?gclid=CjwKCAjwhNWZBhB_EiwAPzlhNtReVIBfrUFBUt6SqZz3YLezP9YEiGuBube4YSTrOF-0ovxzpNGNaRoCiYsQAvD_BwE&gclsrc=aw.ds). **Strongly recommended** | The ViewModel interacts with the data or domain layers using: - Kotlin flows for receiving application data, - `suspend` functions to perform actions using [`viewModelScope`](https://developer.android.com/topic/libraries/architecture/coroutines#viewmodelscope). |
| Use ViewModels at screen level. **Strongly recommended** | Do not use ViewModels in reusable pieces of UI. You should use ViewModels in: - Screen-level composables, - Activities/Fragments in Views, - Destinations or graphs when using [Jetpack Navigation](https://developer.android.com/guide/navigation). |
| Use [plain state holder classes](https://developer.android.com/topic/architecture/ui-layer/stateholders#ui-logic) in reusable UI components. **Strongly recommended** | Use [plain state holder classes](https://developer.android.com/topic/architecture/ui-layer/stateholders#ui-logic) for handling complexity in reusable UI components. By doing this, the state can be hoisted and controlled externally. |
| Do not use [`AndroidViewModel`](https://developer.android.com/reference/androidx/lifecycle/AndroidViewModel). **Recommended** | Use the [`ViewModel`](https://developer.android.com/reference/androidx/lifecycle/ViewModel) class, not [`AndroidViewModel`](https://developer.android.com/reference/androidx/lifecycle/AndroidViewModel). The `Application` class shouldn't be used in the ViewModel. Instead, move the dependency to the UI or the data layer. |
| Expose a UI state. **Recommended** | ViewModels should expose data to the UI through a single property called `uiState`. If the UI shows multiple, unrelated pieces of data, the VM can [expose multiple UI state properties](https://developer.android.com/jetpack/guide/ui-layer#additional-considerations). - You should make `uiState` a `StateFlow`. - You should create the `uiState` using the [`stateIn`](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/state-in.html) operator with the [`WhileSubscribed(5000)`](https://medium.com/androiddevelopers/migrating-from-livedata-to-kotlins-flow-379292f419fb) policy [(example)](https://github.com/android/compose-samples/blob/main/JetNews/app/src/main/java/com/example/jetnews/ui/interests/InterestsViewModel.kt#L56) if the data comes as a stream of data from other layers of the hierarchy. - For simpler cases with no streams of data coming from the data layer, it's acceptable to use a `MutableStateFlow` exposed as an immutable `StateFlow` [(example)](https://github.com/android/compose-samples/blob/main/Jetcaster/app/src/main/java/com/example/jetcaster/ui/home/category/PodcastCategoryViewModel.kt#L37). - You can choose to have the `${Screen}UiState` as a data class that can contain data, errors and loading signals. This class could also be a sealed class if the different states are exclusive. |

The following snippet outlines how to expose UI state from a ViewModel:  

    @HiltViewModel
    class BookmarksViewModel @Inject constructor(
        newsRepository: NewsRepository
    ) : ViewModel() {

        val feedState: StateFlow<NewsFeedUiState> =
            newsRepository
                .getNewsResourcesStream()
                .mapToFeedState(savedNewsResourcesState)
                .stateIn(
                    scope = viewModelScope,
                    started = SharingStarted.WhileSubscribed(5_000),
                    initialValue = NewsFeedUiState.Loading
                )

        // ...
    }

## Lifecycle

The following are some best practices for working with the [Android
lifecycle](https://developer.android.com/guide/components/activities/activity-lifecycle):

| Recommendation | Description |
|---|---|
| Do not override lifecycle methods in Activities or Fragments. **Strongly recommended** | Do not override lifecycle methods such as `onResume` in Activities or Fragments. Use [`LifecycleObserver`](https://developer.android.com/reference/androidx/lifecycle/LifecycleObserver) instead. If the app needs to perform work when the lifecycle reaches a certain `Lifecycle.State`, use the [`repeatOnLifecycle`](https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#(androidx.lifecycle.Lifecycle).repeatOnLifecycle(androidx.lifecycle.Lifecycle.State,kotlin.coroutines.SuspendFunction1)) API. |

The following snippet outlines how to perform operations given a certain
Lifecycle state:  

### Views

    class MyFragment: Fragment() {
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)

            viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
                override fun onResume(owner: LifecycleOwner) {
                    // ...
                }
                override fun onPause(owner: LifecycleOwner) {
                    // ...
                }
            }
        }
    }

### Compose

    @Composable
    fun MyApp() {

        val lifecycleOwner = LocalLifecycleOwner.current
        DisposableEffect(lifecycleOwner, ...) {
            val lifecycleObserver = object : DefaultLifecycleObserver {
                override fun onStop(owner: LifecycleOwner) {
                    // ...
                }
            }

            lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
            onDispose {
                lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
            }
        }
    }

## Handle dependencies

There are several best practices you should observe when managing dependencies
between components:

| Recommendation | Description |
|---|---|
| Use [dependency injection](https://developer.android.com/training/dependency-injection). **Strongly recommended** | Use [dependency injection](https://developer.android.com/training/dependency-injection) best practices, mainly [constructor injection](https://developer.android.com/training/dependency-injection#what-is-di) when possible. |
| Scope to a component when necessary. **Strongly recommended** | Scope to a [dependency container](https://developer.android.com/training/dependency-injection/manual#dependencies-container) when the type contains mutable data that needs to be shared or the type is expensive to initialize and is widely used in the app. |
| Use [Hilt](https://developer.android.com/training/dependency-injection/hilt-android). **Recommended** | Use [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) or [manual dependency injection](https://developer.android.com/training/dependency-injection/manual) in simple apps. Use [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) if your project is complex enough. For example, if you have: - Multiple screens with ViewModels---integration - WorkManager usage---integration - Advance usage of Navigation, such as ViewModels scoped to the nav graph---integration. |

## Testing

The following are some best practices for [testing](https://developer.android.com/training/testing/fundamentals):

| Recommendation | Description |
|---|---|
| [Know what to test](https://developer.android.com/training/testing/fundamentals/what-to-test). **Strongly recommended** | Unless the project is roughly as simple as a hello world app, you should test it, at minimum with: - Unit test ViewModels, including Flows. - Unit test data layer entities. That is, repositories and data sources. - UI navigation tests that are useful as regression tests in CI. |
| Prefer fakes to mocks. **Strongly recommended** | Read more in the [Use test doubles in Android documentation](https://developer.android.com/training/testing/fundamentals/test-doubles). |
| Test StateFlows. **Strongly recommended** | When testing `StateFlow`: - [Assert on the `value` property](https://developer.android.com/kotlin/flow/test#stateflows) whenever possible - You should [create a `collectJob`](https://developer.android.com/kotlin/flow/test#statein) if using `WhileSubscribed` |

For more information, check the [What to test in Android DAC guide](https://developer.android.com/training/testing/fundamentals/what-to-test).

## Models

You should observe these best practices when developing models in your apps:

| Recommendation | Description |
|---|---|
| Create a model per layer in complex apps. **Recommended** | In complex apps, create new models in different layers or components when it makes sense. Consider the following examples: - A remote data source can map the model that it receives through the network to a simpler class with just the data the app needs - Repositories can map DAO models to simpler data classes with just the information the UI layer needs. - ViewModel can include data layer models in `UiState` classes. |

## Naming conventions

When naming your codebase, you should be aware of the following best practices:

| Recommendation | Description |
|---|---|
| Naming methods. **Optional** | Methods should be a verb phrase. For example, `makePayment()`. |
| Naming properties. **Optional** | Properties should be a noun phrase. For example, `inProgressTopicSelection`. |
| Naming streams of data. **Optional** | When a class exposes a Flow stream, LiveData, or any other stream, the naming convention is `get{model}Stream()`. For example, `getAuthorStream(): Flow<Author>` If the function returns a list of models the model name should be in the plural: `getAuthorsStream(): Flow<List<Author>>` |
| Naming interfaces implementations. **Optional** | Names for the implementations of interfaces should be meaningful. Have `Default` as the prefix if a better name cannot be found. For example, for a `NewsRepository` interface, you could have an `OfflineFirstNewsRepository`, or `InMemoryNewsRepository`. If you can find no good name, then use `DefaultNewsRepository`. Fake implementations should be prefixed with `Fake`, as in `FakeAuthorsRepository`. |