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
ProductRepositoryque gestione una lista de productos. - Crea un
ProductViewModelque exponga los productos a la vista. - Diseña una vista que observe los datos del
ProductViewModely 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
