đź•’ Mini-CronĂłmetro en Android con Kotlin y Coroutines (Ejercicio paso a paso)


En esta entrada te propongo un ejercicio práctico y guiado para Android en Kotlin, donde construirás una app sencilla de un cronómetro progresivo usando Coroutines. Es una versión simplificada del clásico ejercicio con múltiples cronos.

Ideal si estás aprendiendo Android y quieres practicar:

  • Interfaces con EditText, TextView y Button
  • Uso de Coroutines para tareas asĂ­ncronas
  • LĂłgica básica de control y validaciĂłn

🎯 ¿Qué vamos a hacer?

Una app que permita al usuario:

  • Ingresar un nĂşmero máximo de segundos
  • Iniciar el conteo desde cero hasta ese nĂşmero
  • Detenerlo o reiniciarlo en cualquier momento

Todo esto se mostrará en una interfaz limpia, sin complicaciones.


đź§° Requisitos

  • Android Studio actualizado
  • Kotlin como lenguaje
  • SDK mĂ­nimo: 21 (Android 5.0 Lollipop)
  • Coroutines habilitadas

1. đź›  Crear el proyecto

  1. Abre Android Studio
  2. Selecciona New Project > Empty Activity
  3. Nombra el proyecto MiniCronometro
  4. Elige Kotlin como lenguaje y minSdk 21

2. ⚙️ Configurar dependencias

Abre tu archivo build.gradle (Module: app) y agrega estas líneas si no están:

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
}

Luego sincroniza tu proyecto.


3. đź§© Crear la interfaz (activity_main.xml)

Copia esto dentro de tu archivo 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:padding="24dp"
    android:orientation="vertical"
    android:gravity="center_horizontal">

    <EditText
        android:id="@+id/editMax"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Máximo en segundos"
        android:inputType="number" />

    <TextView
        android:id="@+id/txtCounter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="0"
        android:textSize="64sp"
        android:layout_marginTop="24dp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_marginTop="24dp">

        <Button
            android:id="@+id/btnStart"
            android:text="Iniciar" />

        <Button
            android:id="@+id/btnStop"
            android:text="Detener"
            android:layout_marginStart="8dp" />

        <Button
            android:id="@+id/btnReset"
            android:text="Reiniciar"
            android:layout_marginStart="8dp" />
    </LinearLayout>
</LinearLayout>

4. đź§  LĂłgica en Kotlin (MainActivity.kt)

Reemplaza el contenido de MainActivity.kt con este:

class MainActivity : AppCompatActivity() {

    private lateinit var txtCounter: TextView
    private var job: Job? = null
    private var current = 0
    private var max = 0
    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val editMax = findViewById<EditText>(R.id.editMax)
        txtCounter = findViewById(R.id.txtCounter)
        val btnStart = findViewById<Button>(R.id.btnStart)
        val btnStop = findViewById<Button>(R.id.btnStop)
        val btnReset = findViewById<Button>(R.id.btnReset)

        btnStart.setOnClickListener {
            max = editMax.text.toString().toIntOrNull() ?: 0
            if (max in 1..9999) {
                startCounter()
            } else {
                editMax.error = "Introduce un número válido (1 a 9999)"
            }
        }

        btnStop.setOnClickListener {
            job?.cancel()
        }

        btnReset.setOnClickListener {
            job?.cancel()
            current = 0
            txtCounter.text = "0"
        }
    }

    private fun startCounter() {
        job?.cancel()
        job = scope.launch {
            while (current < max) {
                delay(1000)
                current++
                txtCounter.text = current.toString()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        scope.cancel()
    }
}

đź§Ş Prueba final

  1. Escribe un nĂşmero (por ejemplo, 10)
  2. Pulsa Iniciar
  3. Verás cómo aumenta el contador cada segundo
  4. Puedes detener o reiniciar en cualquier momento

đź§± Ideas para ampliarlo

  • Agregar un ProgressBar
  • NotificaciĂłn cuando llegue al máximo
  • Vibrar o reproducir sonido al finalizar
  • Guardar estado usando ViewModel

âś… ConclusiĂłn

Este mini-ejercicio te permite entender cómo usar coroutines para manejar tareas temporizadas sin bloquear la interfaz de usuario. Si ya te manejas con este, ¡puedes animarte a hacer un multicronómetro con RecyclerView como el del ejemplo más avanzado!


ÂżTe gustarĂ­a que subiera este cĂłdigo completo a GitHub? ÂżQuieres un vĂ­deo paso a paso?
Déjamelo en los comentarios 👇

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Información básica sobre protección de datos Ver más

  • Responsable: Tomas Gonzalez.
  • Finalidad:  Moderar los comentarios.
  • LegitimaciĂłn:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento:  No se ceden o comunican datos a terceros para prestar este servicio.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • InformaciĂłn Adicional: Puede consultar la informaciĂłn detallada en la PolĂ­tica de Privacidad.

error: Content is protected !!
Este sitio web utiliza cookies, si necesitas más informaciĂłn puedes visitar nuestra polĂ­tica de privacidad   
Privacidad