Nesta página, apresentamos várias práticas recomendadas e sugestões para a Arquitetura. Adote nossas dicas para melhorar a qualidade, robustez e escalonabilidade do app. Elas também facilitam os processos de manutenção e teste do app.
As práticas recomendadas abaixo estão agrupadas por assunto. Um nível de importância foi atribuído a cada uma delas, de acordo com a recomendação. Os níveis são os seguintes:
- Altamente recomendável:implemente essa prática, a menos que ela entre em conflito direto com sua abordagem.
- Recomendável: essa prática provavelmente vai melhorar seu app.
- Opcional: essa prática pode melhorar seu app em algumas circunstâncias.
Arquitetura com camadas
A arquitetura com camadas recomendada favorece a separação de conceitos. Ela baseia a IU em modelos de dados, segue os princípios de fonte única de verdade e de fluxo de dados unidirecional. Confira algumas práticas recomendadas para arquitetura com camadas:
| Recomendação | Descrição |
|---|---|
| Usar uma camada de dados claramente definida.
Altamente recomendável |
A camada de dados expõe os dados do aplicativo ao restante do app e contém a grande maioria da lógica de negócios dele.
|
| Usar uma camada de IU claramente definida.
Altamente recomendável |
A camada de IU mostra os dados do app na tela e atua como o ponto principal de interação do usuário. O Jetpack Compose é o kit de ferramentas moderno recomendado para criar a interface do seu app.
|
| Exponha os dados do aplicativo da camada de dados usando um repositório.
Altamente recomendável |
Verifique se os componentes na camada da interface, como elementos combináveis ou ViewModels, não interagem diretamente com uma fonte de dados. Exemplos de fontes de dados:
|
| Usar corrotinas e fluxos.
Altamente recomendável |
Usar corrotinas e fluxos para estabelecer a comunicação entre as camadas.
Para mais informações sobre práticas recomendadas de corrotinas, consulte Práticas recomendadas para corrotinas no Android. |
| Usar uma camada de domínios.
Ideal para apps grandes |
Use uma camada de domínio com casos de uso se precisar reutilizar a lógica de negócios que interage com a camada de dados em vários ViewModels ou se quiser simplificar a complexidade da lógica de negócios de um ViewModel específico. |
Camada de IU
A função da camada de IU é mostrar os dados do app na tela e atuar como o ponto principal de interação do usuário. Confira algumas práticas recomendadas para a camada de IU:
| Recomendação | Descrição |
|---|---|
| Seguir o fluxo de dados unidirecional (UDF, na sigla em inglês).
Altamente recomendável |
Siga os princípios do fluxo de dados unidirecional (UDF), em que os ViewModels expõem o estado da interface usando o padrão de observador e recebem ações da interface por chamadas de método. |
| Usar os ViewModels do AAC, caso sejam vantajosos para o app.
Altamente recomendável |
Use ViewModels do AAC para processar a lógica de negócios e busque dados do app para expor o estado da interface à interface.
Para mais informações sobre as práticas recomendadas do ViewModel, consulte Recomendações de arquitetura. Para mais informações sobre os benefícios dos ViewModels, consulte O ViewModel como um detentor de estado da lógica de negócios. |
| Usar a coleta de estado da IU com reconhecimento de ciclo de vida.
Altamente recomendável |
Colete o estado da interface usando o builder adequado de corrotinas com reconhecimento de ciclo de vida, collectAsStateWithLifecycle.
Saiba mais sobre o |
| Não enviar eventos do ViewModel para a IU.
Altamente recomendável |
Processe o evento imediatamente no ViewModel e cause uma atualização de estado com o resultado. Para mais informações sobre eventos da interface, consulte Processar eventos do ViewModel. |
| Usar um aplicativo de atividade única.
Altamente recomendável |
Use a Navegação 3 para alternar entre as diferentes telas e links diretos para o app, caso ele tenha mais de uma tela. |
| Usar o Jetpack Compose.
Altamente recomendável |
Use o Jetpack Compose para criar novos apps para smartphones, tablets, dispositivos dobráveis e Wear OS. |
O snippet abaixo descreve como coletar o estado da IU de uma forma que reconhece o ciclo de vida:
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
Os ViewModels são responsáveis por fornecer o estado da UI e acessar a camada de dados. Confira algumas práticas recomendadas para ViewModels:
| Recomendação | Descrição |
|---|---|
| Mantenha os ViewModels independentes do ciclo de vida do Android.
Altamente recomendável |
Nos ViewModels, não mantenha uma referência a nenhum tipo relacionado ao ciclo de vida. Não transmita Activity, Context ou Resources como uma dependência.
Caso um Context seja necessário no ViewModel, analise se esse elemento está na camada certa. |
| Usar corrotinas e fluxos.
Altamente recomendável |
O ViewModel interage com as camadas de dados ou de domínio usando o seguinte:
|
| Usar ViewModels na tela.
Altamente recomendável |
Não use ViewModels em partes reutilizáveis da IU. Em vez disso, use-os em:
|
| Use classes de detentores de estado simples em componentes de IU reutilizáveis.
Altamente recomendável |
Use classes de detentores de estado simples para processar a complexidade em componentes de IU reutilizáveis. Quando você faz isso, o estado pode ser elevado e controlado externamente. |
Não use o AndroidViewModel.
Recomendável |
Use a classe ViewModel, e não AndroidViewModel. Não use a classe Application no ViewModel. Em vez disso, mova a dependência para a IU ou para a camada de dados. |
| Expor um estado da IU.
Recomendável |
Faça com que seus ViewModels exponham dados à interface usando uma única propriedade chamada uiState. Se a IU mostrar diferentes dados não relacionados, a VM pode expor várias propriedades do estado da IU.
|
O snippet abaixo demonstra como expor o estado da IU de um 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
Siga as práticas recomendadas para trabalhar com o ciclo de vida da atividade:
| Recomendação | Descrição |
|---|---|
Use efeitos com reconhecimento de ciclo de vida em combináveis em vez de substituir callbacks do ciclo de vida Activity.
Altamente recomendável |
Não substitua os métodos do ciclo de vida
|
O snippet abaixo descreve como executar operações de acordo com um determinado estado do 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)
}
}
}
Gerenciar dependências
Siga as práticas recomendadas ao gerenciar dependências entre componentes:
| Recomendação | Descrição |
|---|---|
| Usar a injeção de dependência.
Altamente recomendável |
Quando possível, use as práticas recomendadas de injeção de dependência, principalmente a injeção de construtor. |
| Definir um componente como escopo quando necessário.
Altamente recomendável |
Defina um contêiner de dependência como escopo caso o tipo contenha dados mutáveis que precisem ser compartilhados ou caso ele demande muita memória e bateria para inicializar e seja amplamente usado no app. |
| Usar o Hilt.
Recomendável |
Use o Hilt ou a injeção manual de dependência em apps simples. Use o Hilt se o projeto for complexo o suficiente, por exemplo, se ele incluir qualquer um dos seguintes itens:
|
Teste
Confira algumas práticas recomendadas para testes:
| Recomendação | Descrição |
|---|---|
| Saiba o que testar.
Altamente recomendável |
A menos que o projeto seja tão simples quanto um app "hello world", teste-o. No mínimo, inclua o seguinte:
|
| Usar falsificações em vez de simulações.
Altamente recomendável |
Para mais informações sobre o uso de fakes, consulte Usar testes duplos no Android. |
| Testar StateFlows.
Altamente recomendável |
Ao testar StateFlow, faça o seguinte:
|
Para mais informações, consulte O que testar no Android e Testar o layout do Compose.
Modelos
Considere as práticas recomendadas abaixo ao desenvolver modelos nos seus apps:
| Recomendação | Descrição |
|---|---|
| Criar um modelo por camada em apps complexos.
Recomendável |
Em apps complexos, crie novos modelos em camadas ou componentes diferentes quando apropriado. Confira estes exemplos:
|
Convenções de nomenclatura
Ao definir a nomenclatura da base de código, é necessário considerar estas práticas recomendadas:
| Recomendação | Descrição |
|---|---|
| Nomear métodos.
Opcional |
Use frases verbais para nomear métodos, por exemplo, makePayment(). |
| Nomear propriedades.
Opcional |
Use frases nominais para nomear propriedades, por exemplo, inProgressTopicSelection. |
| Nomear fluxos de dados.
Opcional |
Quando uma classe expõe um fluxo de dados ou qualquer outro fluxo, a convenção de nomenclatura é get{model}Stream. Por exemplo, getAuthorStream(): Flow<Author>.
Se a função retornar uma lista de modelos, use o nome do modelo no plural: getAuthorsStream(): Flow<List<Author>>. |
| Nomear implementações de interfaces.
Opcional |
Use nomes significativos para as implementações de interfaces. Defina Default como prefixo, se não encontrar um nome mais adequado. Por exemplo, para uma interface NewsRepository, é possível usar OfflineFirstNewsRepository ou InMemoryNewsRepository. Se não encontrar um nome melhor, use DefaultNewsRepository.
Adicione o prefixo Fake às implementações falsas, como em FakeAuthorsRepository. |
Outros recursos
Para mais informações sobre a arquitetura do Android, consulte os seguintes recursos: