En esta página, se presentan varias recomendaciones y prácticas recomendadas para la arquitectura. Adopta estas funciones para mejorar la calidad, la solidez y la escalabilidad de tu app. También facilitan el mantenimiento y la prueba de tu app.
Las siguientes prácticas recomendadas se agrupan por tema. Cada una tiene una prioridad que refleja cuán recomendable es según el equipo. La lista de prioridades es la siguiente:
- Muy recomendada: Implementa esta práctica, a menos que entre en conflicto con tu estrategia.
- Recomendada: Es probable que esta práctica mejore tu app.
- Opcional: Esta práctica puede mejorar tu app en determinadas circunstancias.
Arquitectura en capas
En la arquitectura en capas que recomendamos, se prefiere la separación de problemas. Controla la IU a partir de modelos de datos, cumple con el principio de fuente de confianza única y sigue los principios del flujo unidireccional de datos. Estas son algunas prácticas recomendadas para la arquitectura en capas:
| Recomendación | Descripción |
|---|---|
| Usa una capa de datos claramente definida.
Muy recomendada |
La capa de datos expone los datos de la aplicación al resto de la app y contiene la gran mayoría de su lógica empresarial.
|
| Usa una capa de la IU claramente definida.
Muy recomendada |
La capa de la IU muestra los datos de la aplicación en la pantalla y sirve como punto principal de la interacción con el usuario. Jetpack Compose es el kit de herramientas moderno recomendado para compilar la IU de tu app.
|
| Expón los datos de la aplicación desde la capa de datos con un repositorio.
Muy recomendada |
Asegúrate de que los componentes de la capa de la IU, como los elementos componibles o los ViewModels, no interactúen directamente con una fuente de datos. Estos son algunos ejemplos de fuentes de datos:
|
| Usa corrutinas y flujos.
Muy recomendada |
Usa corrutinas y flujos para establecer la comunicación entre capas.
Para obtener más información sobre las prácticas recomendadas para corrutinas, consulta Prácticas recomendadas para corrutinas en Android. |
| Usa una capa de dominio.
Recomendada en apps grandes |
Usa una capa de dominio con casos de uso si necesitas reutilizar la lógica empresarial que interactúa con la capa de datos en varios ViewModels o si deseas simplificar la complejidad de la lógica empresarial de un ViewModel en particular. |
Capa de la IU
La función de la capa de la IU es mostrar los datos de la aplicación en la pantalla y servir como punto principal de interacción con el usuario. Estas son algunas prácticas recomendadas para la capa de la IU:
| Recomendación | Descripción |
|---|---|
| Sigue el Flujo unidireccional de datos.
Muy recomendada |
Sigue los principios del flujo unidireccional de datos, en el que los ViewModels exponen el estado de la IU usando el patrón del observador y reciben acciones de la IU a través de llamadas de método. |
| Usa AAC de ViewModels si sus beneficios se aplican a tu app.
Muy recomendada |
Usa AAC ViewModels para controlar la lógica empresarial y recuperar datos de la aplicación a fin de exponer el estado de la IU a la IU.
Para obtener más información sobre las prácticas recomendadas de ViewModel, consulta Recomendaciones de arquitectura. Para obtener más información sobre los beneficios de los ViewModels, consulta El ViewModel como contenedor de estado de lógica empresarial. |
| Usa la recopilación de estado de la IU optimizada para ciclos de vida.
Muy recomendada |
Recopila el estado de la IU con el compilador de corrutinas optimizado para ciclos de vida adecuado, collectAsStateWithLifecycle.
Obtén más información sobre |
| No envíes eventos del ViewModel a la IU.
Muy recomendada |
Procesa el evento inmediatamente en ViewModel y genera una actualización de estado con el resultado del control del evento. Para obtener más información sobre los eventos de la IU, consulta Cómo controlar eventos de ViewModel. |
| Usa una aplicación de una sola actividad.
Muy recomendada |
Usa Navigation 3 para navegar entre pantallas y establecer vínculos directos a tu app si esta tiene más de una pantalla. |
| Usa Jetpack Compose.
Muy recomendada |
Usa Jetpack Compose para compilar apps nuevas para teléfonos, tablets, dispositivos plegables y Wear OS. |
En el siguiente fragmento, se describe cómo recopilar el estado de la IU de manera optimizada para los ciclos de vida:
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
Los ViewModels son responsables de proporcionar el estado de la IU y acceder a la capa de datos. Estas son algunas prácticas recomendadas para ViewModels:
| Recomendación | Descripción |
|---|---|
| Mantén los ViewModels independientes del ciclo de vida de Android.
Muy recomendada |
En los ViewModels, no conserves una referencia a ningún tipo relacionado con el ciclo de vida. No pases Activity, Context ni Resources como dependencia.
Si algo necesita un Context en el ViewModel, evalúa con atención si está en la capa correcta. |
| Usa corrutinas y flujos.
Muy recomendada |
ViewModel interactúa con las capas de datos o de dominio de la siguiente manera:
|
| Usa ViewModels a nivel de la pantalla.
Muy recomendada |
No uses ViewModels en piezas de IU reutilizables. Debes usar ViewModels en lo siguiente:
|
| Usa clases contenedoras de estados sin formato en componentes de IU reutilizables.
Muy recomendada |
Usa clases contenedoras de estados sin formato para controlar la complejidad en componentes de IU reutilizables. Cuando haces esto, el estado se puede elevar y controlar de forma externa. |
No uses AndroidViewModel.
Recomendada |
Usa la clase ViewModel, no AndroidViewModel. No uses la clase Application en ViewModel. En su lugar, mueve la dependencia a la IU o a la capa de datos. |
| Expón un estado de IU.
Recomendado |
Haz que tus ViewModels expongan datos a la IU a través de una sola propiedad llamada uiState. Si la IU muestra varios datos no relacionados, la VM puede exponer varias propiedades del estado de la IU.
|
En el siguiente fragmento, se describe cómo exponer el estado de la IU desde un 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
)
// ...
}
Ciclo de vida
Sigue las prácticas recomendadas para trabajar con el ciclo de vida de la actividad:
| Recomendación | Descripción |
|---|---|
Usa efectos optimizados para ciclos de vida en elementos componibles en lugar de anular las devoluciones de llamada del ciclo de vida de Activity.
Muy recomendada |
No anules los métodos de ciclo de vida de
|
En el siguiente fragmento, se describe cómo realizar operaciones en función de un determinado estado de ciclo de vida:
@Composable
fun LocationChangedEffect(
locationManager: LocationManager,
onLocationChanged: (Location) -> Unit
) {
val currentOnLocationChanged by rememberUpdatedState(onLocationChanged)
LifecycleStartEffect(locationManager) {
val listener = LocationListener { newLocation ->
currentOnLocationChanged(newLocation)
}
try {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000L,
1f,
listener,
)
} catch (e: SecurityException) {
// TODO: Handle missing permissions
}
onStopOrDispose {
locationManager.removeUpdates(listener)
}
}
}
Control de dependencias
Sigue las prácticas recomendadas cuando administres dependencias entre componentes:
| Recomendación | Descripción |
|---|---|
| Usa la inserción de dependencias.
Muy recomendada |
Usa las prácticas recomendadas de inserción de dependencias, en especial, la inserción del constructor, cuando sea posible. |
| Define el alcance para un componente cuando sea necesario.
Muy recomendada |
Define el alcance para un contenedor de dependencias cuando el tipo contenga datos mutables que se deban compartir o resulte costoso inicializar el tipo y se use mucho en la app. |
| Usa Hilt.
Recomendada |
Usa Hilt o la inserción manual de dependencias en apps simples. Usa Hilt si tu proyecto es lo suficientemente complejo, por ejemplo, si incluye cualquiera de los siguientes elementos:
|
Prueba
Estas son algunas recomendaciones para las pruebas:
| Recomendación | Descripción |
|---|---|
| Comprende qué probar.
Muy recomendada |
A menos que el proyecto sea tan simple como una app de "Hello World", pruébalo. Como mínimo, incluye lo siguiente:
|
| Opta por simulaciones en lugar de muestras.
Muy recomendada |
Para obtener más información sobre el uso de objetos simulados, consulta Cómo usar pruebas dobles en Android. |
| Prueba StateFlows.
Muy recomendada |
Cuando pruebes StateFlow, haz lo siguiente:
|
Para obtener más información, consulta Qué probar en Android y Cómo probar tu diseño de Compose.
Modelos
Ten en cuenta estas prácticas recomendadas cuando desarrolles modelos en tus apps:
| Recomendación | Descripción |
|---|---|
| Crea un modelo por capa en apps complejas.
Recomendada |
En apps complejas, crea modelos nuevos en diferentes capas o componentes cuando hacerlo tenga sentido. Considera los siguientes ejemplos:
|
Convenciones de nombres
A la hora de nombrar tu base de código, debes tener en cuenta las siguientes prácticas recomendadas:
| Recomendación | Descripción |
|---|---|
| Nombra métodos.
Opcional |
Usa frases verbales para nombrar los métodos, por ejemplo, makePayment(). |
| Nombra propiedades.
Opcional |
Usa frases nominales para nombrar propiedades, por ejemplo, inProgressTopicSelection. |
| Nombra flujos de datos.
Opcional |
Cuando una clase expone una transmisión de flujo o cualquier otra, la convención de nombres es get{model}Stream. Por ejemplo, getAuthorStream(): Flow<Author>.
Si la función devuelve una lista de modelos, usa el nombre del modelo en plural: getAuthorsStream(): Flow<List<Author>>. |
| Nombra las implementaciones de interfaces.
Opcional |
Usa nombres significativos para las implementaciones de interfaces. Usa Default como prefijo si no se encuentra un nombre mejor. Por ejemplo, para una interfaz NewsRepository, puedes tener un OfflineFirstNewsRepository o InMemoryNewsRepository. Si no encuentras un nombre adecuado, usa DefaultNewsRepository.
Agrega el prefijo Fake a las implementaciones simuladas, como en FakeAuthorsRepository. |
Recursos adicionales
Para obtener más información sobre la arquitectura de Android, consulta los siguientes recursos adicionales: