Introducci贸n al Patr贸n de Arquitectura MVVM
Domina MVVM: Crea Aplicaciones Reactivas y Escalables en Android
驴Qu茅 es MVVM?
Calorie Tracker: Pantalla de Bienvenida
Quiz: Introducci贸n al Patr贸n de Arquitectura MVVM
Implementaci贸n en MVVM
Views del Onboarding Feature
Navegaci贸n: Rutas y Grafos con Jetpack Compose
ViewModels para el Onboarding Feature
Gesti贸n de inputs con ViewModel
Persistencia de datos e inyecci贸n de dependencias con Hilt
Quiz: Implementaci贸n en MVVM
Pantallas de Seguimiento
Calorie Tracker: Home ScreenView
Calorie Tracker: selector de d铆as y comidas
Quiz: Pantallas de Seguimiento
Networking y Datos
Conexi贸n con la API OpenFood
Calorie Tracker: SearchScreen
Integraci贸n de la API Open Food en la UI
Quiz: Networking y Datos
Persistencia Local
Calorie Tracker: DetailFood View
Creaci贸n de base de datos con ROOM
Integraci贸n de base de datos con ROOM
Quiz: Persistencia Local
Funcionalidades Avanzadas
Boton "Add" en TrackerOverviewScreen
Caso de uso para calcular los nutrientes seleccionados
Serializaci贸n y Navegaci贸n con Datos Complejos
Quiz: Funcionalidades Avanzadas
Lanzamiento de la APP
Lanzamiento de nuestra aplicaci贸n
You don't have access to this class
Keep learning! Join and start boosting your career
In this class we will show you how to create a search screen using atomic components based on the single responsibility principle. In addition, we integrate the OpenFood API consumption functionality through a view model to ensure a clean and efficient architecture.
The single responsibility principle is fundamental to the Model-View-ViewModel (MVVM) architecture. This principle dictates that a class, module or component should be responsible for a single task or responsibility within the system. Applying this approach has several advantages:
searchTextField
component?Let's start by developing the main component of our search screen, the searchTextField
. This component will handle the user's text input and act as the search field.
@Composable fun SearchTextField( text: String, onValueChange: (String) -> Unit, onSearch: () -> Unit, modifier: Modifier = Modifier, hint: String = stringResource(R.string.search), shouldShowHint: Boolean = true, onFocusChange: (FocusState) -> Unit ) { val localSpacing = LocalSpacing.current Box(modifier = modifier) { BasicTextField( value = text, onValueChange = onValueChange, singleLine = true, keyboardActions = KeyboardActions( onSearch = { onSearch() } ), keyboardOptions = KeyboardOptions( imeAction = ImeAction.Search ), modifier = Modifier .clip(RoundedCornerShape(5.dp)) .padding(2.dp) .shadow(2.dp, RoundedCornerShape(5.dp)) .background(MaterialTheme.colors.surface) .fillMaxWidth() .padding(localSpacing.spaceMedium) .onFocusChanged { onFocusChange(it) } .testTag("searchTextField") ) if (shouldShowHint) { Text( text = hint, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Light, color = Color.LightGray, modifier = Modifier.align(Alignment.CenterStart).padding(localSpacing.spaceMedium) ) } } IconButton(onClick = onSearch, modifier = Modifier.align(Alignment.CenterEnd)) { Icon( imageVector = Icons.Default.Search, contentDescription = stringResource(R.string.search) ) } } } } } } }
searchScreen
?Having a robust text component, we can move on to building the full search screen, leveraging the searchTextField
composable we have developed.
@Composable fun SearchScreen( snackbarHostState: SnackbarHostState, mealName: String, dayOfTheMonth: Int, month: Int, year: Int, onNavigateUp: () -> Unit, viewModel: SearchViewModel = hiltViewModel() ) { val localSpacing = LocalSpacing.current val keyboardController = LocalSoftwareKeyboardController.current Column( modifier = Modifier.fillMaxSize().padding(localSpacing.spaceMedium) ) { Spacer(modifier = Modifier.height(localSpacing.spaceLarge)) Text( text = stringResource(id = R.string.add_meal_name, mealName), style = MaterialTheme.typography.titleMedium ) Spacer(modifier = Modifier.height(localSpacing.spaceMedium)) SearchTextField( text = "", onValueChange = {}, onSearch = { keyboardController?.hide() // Search Logic }, shouldShowHint = true, onFocusChange = {} ) Spacer(modifier = Modifier.height(localSpacing.spaceMedium)) } } }
viewModel
to the search flow?In an MVVM architecture, it is crucial to use a ViewModel to manage view states and business logic. Let's initialize our ViewModel to handle the search with the OpenFood API.
@HiltViewModel class SearchViewModel @Inject constructor( private val trackerUseCase: TrackerUseCase ) : ViewModel() { private val _uiEvent = Channel() val uiEvent = _uiEvent.receiveAsFlow() fun executeSearch() { viewModelScope.launch { // Implementing the search logic trackerUseCase.search("pizza") } } } } }
The code structure and modular design allow us to keep each component separate and focused on its specific task. This not only improves the development and maintenance experience, but also provides flexibility for future expansion. In addition, the use of a viewModel
ensures that the business logic remains separate from the UI logic, which facilitates testing and maintenance.
Let's move forward, excited about our applications' ability to deliver dynamic and functional experiences, always optimizing each component we create.
Contributions 0
Questions 0
Want to see more contributions, questions and answers from the community?