Universidad del Quindío
Programa de Ingeniería de Sistemas y Computación
Título: Programación de Aplicaciones Android con Kotlin
Docente: Carlos Andrés Florez V.
La arquitectura de una aplicación Android se basa en componentes como Activities, Fragments, Services y ViewModels. Estos componentes interactúan entre sí para proporcionar una experiencia de usuario fluida y eficiente. De igual manera, en Android se promueve el uso de patrones de diseño y arquitecturas como MVVM (Model-View-ViewModel) para separar las responsabilidades y mejorar la mantenibilidad del código.
La arquitectura MVVM es un patrón de diseño que separa la lógica de negocio, la interfaz de usuario y la gestión del estado en tres componentes principales:
Una aplicación Android está compuesta por varios componentes clave:
El ciclo de vida de un Activity es crucial para entender cómo manejar el estado y los recursos de la aplicación. Las principales etapas del ciclo de vida incluyen:
La interfaz de usuario (UI) en Android se puede construir utilizando dos enfoques principales: el enfoque tradicional basado en XML y el enfoque moderno basado en Jetpack Compose. El enfoque basado en Jetpack Compose adopta principios de programación funcional, facilitando la creación de interfaces de usuario reactivas y declarativas, por otro lado, el enfoque tradicional aunque no es funcional, puede beneficiarse de prácticas funcionales en la gestión del estado y eventos.
En el enfoque tradicional, las interfaces de usuario se definen en archivos XML y se manipulan en el código Kotlin. Aunque este enfoque no es inherentemente funcional, se pueden aplicar principios funcionales al manejar eventos y actualizar la UI. Hay que tener en cuenta que este enfoque puede llevar a un código más imperativo, verboso y con más efectos secundarios.
Por ejemplo, supongamos que tenemos un botón que aumenta un contador cada vez que se presiona, el valor del contador se muestra en un TextView.
Código de la UI
La UI se define en un archivo XML, como activity_main.xml, de la siguiente manera:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="@+id/textViewCounter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="30sp"/>
<Button
android:id="@+id/buttonIncrement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Incrementar"/>
</LinearLayout>
Código Kotlin para la UI
La lógica para manejar el botón y actualizar el TextView se implementa en la Activity. Una actividad típica podría verse así:
class MainActivity : AppCompatActivity() {
private var contador = 0
/*
* onCreate es un método del ciclo de vida de una Activity
* que se llama cuando la Activity es creada.
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) // Se asocia el layout XML
val textViewCounter: TextView = findViewById(R.id.textViewCounter) // Referencia al TextView
val buttonIncrement: Button = findViewById(R.id.buttonIncrement) // Referencia al Button
// Manejar el clic del botón
buttonIncrement.setOnClickListener {
contador++ // Incrementa el contador generando un efecto secundario
textViewCounter.text = contador.toString() // Actualiza el TextView
}
}
}
El código anterior muestra cómo manejar un evento de clic en un botón para incrementar un contador y actualizar la UI. Sin embargo, este enfoque implica efectos secundarios, ya que el estado del contador se modifica directamente dentro del manejador de eventos. Además, es muy verboso y puede volverse difícil de mantener a medida que la aplicación crece en complejidad.
En el enfoque moderno con Jetpack Compose, la UI se define de manera declarativa utilizando funciones composables. Este enfoque facilita la adopción de principios de programación funcional, como la inmutabilidad y las funciones puras.
Jetpack Compose se basa en la idea de que la UI es una función del estado. Cuando el estado cambia, la UI se vuelve a componer automáticamente para reflejar esos cambios, eliminando la necesidad de manejar efectos secundarios explícitos.
En el enfoque de Compose, el mismo ejemplo del contador se implementaría de la siguiente manera:
@Composable
fun Contador() {
var count by remember { mutableStateOf(0) } // Estado manejado funcionalmente
// UI declarativa
Column {
// Mostrar el contador
Text(
text = "Contador: $count"
)
// Botón para incrementar el contador
Button(
onClick = { count++ }, // Lambda para manejar el clic
content = {
Text(
text = "Incrementar"
)
}
)
}
}
Observe cómo en este enfoque, el estado del contador se maneja de manera funcional utilizando remember y mutableStateOf, lo que permite que la UI se actualice automáticamente cuando el estado cambia, sin efectos secundarios explícitos.
Además, cada componente de la UI es una función pura (con @Composable) que recibe propiedades y devuelve una representación de la UI, lo que facilita la reutilización y el razonamiento sobre el código.
Profundizaremos más en estos conceptos en las siguientes secciones del curso.
Profundice en la arquitectura de aplicaciones Android y el ciclo de vida de las actividades. ¿Los composables también tienen un ciclo de vida? Investigue y describa cómo se maneja el ciclo de vida en Jetpack Compose y compare con el ciclo de vida tradicional de una actividad.