La arquitectura MVVM (Model-View-ViewModel) es un patrón de diseño que facilita la separación de la lógica de negocio y la interfaz de usuario en aplicaciones Android. Este patrón ayuda a crear aplicaciones más mantenibles, escalables y testables.
Objetivos del Módulo
- Comprender los conceptos básicos de la arquitectura MVVM.
- Implementar MVVM en una aplicación Android.
- Utilizar ViewModel y LiveData para gestionar y observar datos.
- Integrar un repositorio para la gestión de datos.
Conceptos Clave
- ¿Qué es MVVM?
MVVM es un patrón de diseño que divide la aplicación en tres componentes principales:
- Model: Representa la capa de datos de la aplicación. Gestiona la lógica de negocio y la comunicación con la base de datos o servicios web.
- View: Representa la interfaz de usuario. Observa los datos expuestos por el ViewModel.
- ViewModel: Actúa como un intermediario entre el Model y la View. Gestiona la lógica de presentación y expone los datos que la View necesita.
- Beneficios de MVVM
- Separación de responsabilidades: Cada componente tiene una responsabilidad clara, lo que facilita el mantenimiento y la escalabilidad.
- Testabilidad: La lógica de negocio y de presentación se puede probar de manera independiente.
- Reutilización de código: Los ViewModels pueden ser reutilizados en diferentes vistas.
Implementación de MVVM en Android
Paso 1: Configuración del Proyecto
Asegúrate de tener las siguientes dependencias en tu archivo build.gradle
:
dependencies { implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" }
Paso 2: Crear el Modelo (Model)
El modelo representa la fuente de datos. Puede ser una base de datos, una API o cualquier otra fuente de datos.
Paso 3: Crear el Repositorio
El repositorio actúa como una fuente única de verdad para los datos. Gestiona la lógica de obtención y almacenamiento de datos.
class UserRepository { private val users = listOf( User(1, "John Doe", "[email protected]"), User(2, "Jane Smith", "[email protected]") ) fun getUsers(): List<User> { return users } }
Paso 4: Crear el ViewModel
El ViewModel expone los datos que la vista necesita y gestiona la lógica de presentación.
class UserViewModel : ViewModel() { private val userRepository = UserRepository() private val _users = MutableLiveData<List<User>>() val users: LiveData<List<User>> get() = _users init { loadUsers() } private fun loadUsers() { _users.value = userRepository.getUsers() } }
Paso 5: Crear la Vista (View)
La vista observa los datos expuestos por el ViewModel y actualiza la interfaz de usuario en consecuencia.
<!-- res/layout/activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/userTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Users" /> </LinearLayout>
// MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var userViewModel: UserViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) userViewModel = ViewModelProvider(this).get(UserViewModel::class.java) val userTextView: TextView = findViewById(R.id.userTextView) userViewModel.users.observe(this, Observer { users -> userTextView.text = users.joinToString { it.name } }) } }
Ejercicio Práctico
Ejercicio
- Crea una aplicación Android que utilice la arquitectura MVVM para mostrar una lista de productos.
- Implementa un
ProductRepository
que gestione una lista de productos. - Crea un
ProductViewModel
que exponga los productos a la vista. - Diseña una vista que observe los datos del
ProductViewModel
y los muestre en unRecyclerView
.
Solución
Paso 1: Crear el Modelo
Paso 2: Crear el Repositorio
class ProductRepository { private val products = listOf( Product(1, "Laptop", 999.99), Product(2, "Smartphone", 499.99) ) fun getProducts(): List<Product> { return products } }
Paso 3: Crear el ViewModel
class ProductViewModel : ViewModel() { private val productRepository = ProductRepository() private val _products = MutableLiveData<List<Product>>() val products: LiveData<List<Product>> get() = _products init { loadProducts() } private fun loadProducts() { _products.value = productRepository.getProducts() } }
Paso 4: Crear la Vista
<!-- res/layout/activity_main.xml --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/productRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
// MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var productViewModel: ProductViewModel private lateinit var productAdapter: ProductAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) productViewModel = ViewModelProvider(this).get(ProductViewModel::class.java) val productRecyclerView: RecyclerView = findViewById(R.id.productRecyclerView) productAdapter = ProductAdapter() productRecyclerView.layoutManager = LinearLayoutManager(this) productRecyclerView.adapter = productAdapter productViewModel.products.observe(this, Observer { products -> productAdapter.submitList(products) }) } }
// ProductAdapter.kt class ProductAdapter : ListAdapter<Product, ProductAdapter.ProductViewHolder>(ProductDiffCallback()) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item_product, parent, false) return ProductViewHolder(view) } override fun onBindViewHolder(holder: ProductViewHolder, position: Int) { holder.bind(getItem(position)) } class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private val productNameTextView: TextView = itemView.findViewById(R.id.productNameTextView) private val productPriceTextView: TextView = itemView.findViewById(R.id.productPriceTextView) fun bind(product: Product) { productNameTextView.text = product.name productPriceTextView.text = product.price.toString() } } class ProductDiffCallback : DiffUtil.ItemCallback<Product>() { override fun areItemsTheSame(oldItem: Product, newItem: Product): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: Product, newItem: Product): Boolean { return oldItem == newItem } } }
Conclusión
En esta sección, hemos aprendido a implementar la arquitectura MVVM en una aplicación Android. Hemos visto cómo separar la lógica de negocio y la interfaz de usuario utilizando ViewModel y LiveData. Esta arquitectura no solo mejora la mantenibilidad y escalabilidad de la aplicación, sino que también facilita la realización de pruebas unitarias y de integración. En el siguiente módulo, exploraremos la inyección de dependencias con Dagger para mejorar aún más la modularidad y testabilidad de nuestras aplicaciones.
Curso de Android Studio
Módulo 1: Introducción a Android Studio
- Introducción a Android Studio
- Configuración de Android Studio
- Entendiendo la interfaz de Android Studio
- Creando tu primer proyecto Android
Módulo 2: Desarrollo básico de Android
- Entendiendo la estructura del proyecto Android
- Introducción a los diseños XML
- Componentes básicos de la interfaz de usuario
- Introducción a las actividades
- Ejecutando tu aplicación en un emulador
Módulo 3: Desarrollo intermedio de Android
- Introducción a los Intents
- Trabajando con Fragmentos
- Manejo de la entrada del usuario
- Usando RecyclerView
- Redes en Android
Módulo 4: Desarrollo avanzado de Android
- Persistencia de datos con SQLite
- Usando Room para la gestión de bases de datos
- Componentes avanzados de la interfaz de usuario
- Vistas personalizadas y Canvas
- Trabajando con tareas en segundo plano
Módulo 5: Desarrollo profesional de Android
- Implementando la arquitectura MVVM
- Inyección de dependencias con Dagger
- Pruebas unitarias y pruebas de interfaz de usuario
- Publicando tu aplicación en Google Play
- Optimización del rendimiento