sábado, 21 de enero de 2012

Cronometro en Android con Thread.

Continuo intentando hacer mi primera aplicación en Android. Necesitaba usar Thread para tener un cronómetro e ir contando el tiempo que va pasando en la aplicación y tener un coste en función del tiempo.
Para ello necesito tres botones, uno de arrancar, uno de pause y otro de reiniciar. Además dos TextView que son donde representaré el cronómetro y el coste.
El main.xml que se necesita para definir los botones es:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
        <TextView
        android:id="@+id/txtReloj"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />               
        <TextView
        android:id="@+id/txtImporte"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        />       
         <Button
          android:id="@+id/BtnArrancar"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
           />
         <Button
          android:id="@+id/BtnPausar"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
           />
         <Button
          android:id="@+id/BtnParar"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
           />     
</LinearLayout>


 El java principal que ejecutamos cuando arrancamos solamente se encarga de arrancar el hilo y deshabilitar los botones. Además cuando queremos reiniciar el contador ponemos los textView con el número que nos interesa. Os dejo el Cron.java:
package Android.Com.Cronometro;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.app.Activity;
import android.widget.Button;
import android.widget.TextView;

public class Cron extends Activity {
   
    //Definimos las variables que usaremos. Texto, botones, String e Hilo.
    public TextView txtReloj;
    public TextView txtImporte;
    Button btnArrancar;
    Button btnPausar;
    Button btnParar;
    Boolean arranque=false;
    Boolean pause=false;
    double precio=60; //Precio en €/hora
    private String crono;
    private String crono2;
    MiHilo mihilo;
    public TextView txtTiempo;
       
  @Override
  public void onCreate(Bundle savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
   
    //Asociamos variables con main.xml
    txtReloj = (TextView) findViewById(R.id.txtReloj);
    txtImporte = (TextView) findViewById(R.id.txtImporte);
    btnArrancar = (Button) findViewById(R.id.BtnArrancar);
    btnPausar = (Button) findViewById(R.id.BtnPausar);
    btnParar = (Button) findViewById(R.id.BtnParar);
   
    //Establecemos texto en los botones y arrancamos el hilo
    mihilo = new MiHilo(txtReloj,precio,txtImporte);
    btnArrancar.setText("Arrancar");
    btnPausar.setText("Pausar");
    btnParar.setText("Parar");
    mihilo.start();
           
    //Listener del botón Arrancar
    btnArrancar.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v){
           
                //Pongo el hilo a funcionar, los boolean a arrancado y no pause y actualizo botones
                mihilo.setPausado(false);
                mihilo.setDetenido(false);
              
                btnArrancar.setEnabled(false);
                btnParar.setEnabled(false);
                btnPausar.setEnabled(true);
        }
       
    });
   
    //Listener del botón pausar
    btnPausar.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v){
           
                //Cuando aprieto el pause
                mihilo.setPausado(true);
               
                btnArrancar.setEnabled(true);
                btnParar.setEnabled(true);
                btnPausar.setEnabled(false);
        }
       
    });
   
    //Listener del botón parar
    btnParar.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v){
           
                //Cuando aprieto el parar
                btnArrancar.setEnabled(true);
                btnParar.setEnabled(false);
                btnPausar.setEnabled(false);
               
                mihilo.setCentesimas(0);
                mihilo.setSegundos(0);
                mihilo.setMinutos(0);
                mihilo.setHoras(0);
                mihilo.setEuros(0);
                               
                crono = "00:00:00:00";
                crono2 = "000,00";
                txtReloj.setText(crono);
                txtImporte.setText(crono2);
               
                mihilo.setPausado(true);
        }
       
    });
      
  }
}
Ahora viene el archivo del thread que va incrementando los contadores. En verdad tiene un desfase con el tiempo real ya que el tiempo que se emplea en realizar el método se va añadiendo como desfase. Lo que hago entonces es esperar 9 milisegundos en vez de 10 para ir compensando ese desfase. Cada vez que lo ejecuto llamo al handler que es vínculo entre la interfaz y el hilo principal. El MiHilo.java quedaría como sigue:

package Android.Com.Cronometro;

import android.widget.TextView;

public class MiHilo extends Thread
{
        public boolean detenido;
        public boolean pausado;
        double euros = 00;
        int centesimas = 00,minutos=00, segundos=00, horas=00;
        double precio;
        Hand handler,handler2;
        String cron,cron2;
        Cron c;
       
        //Cuando incio el hilo ya está detenido a false y pausado a true
        public MiHilo(TextView t, double p, TextView cs)
        {
                precio = p/3600;
                c = new Cron();
                detenido = false;
                pausado = true;
                handler = new Hand(t);
                handler2 = new Hand(cs);
        }
       
        @SuppressWarnings("static-access")
        public void run()
        {      
        while(!detenido)
          {
            while(!pausado)
            {
              try {                 
                if(centesimas == 99){
                        centesimas = 00;
                        segundos++;
                        euros=euros+precio;
                }
                if (segundos == 59) {
                  segundos = 00;
                  minutos++;
                }
                if (minutos == 59) {
                  minutos = 00;
                  horas++;
                }
               
                centesimas++;
               
                cron2 = euros+"";
                cron = horas + " : " + minutos + " : " + segundos + " : " + centesimas;
                handler.setHcron(cron);
                handler2.setHcron(cron2);
                handler.act();
                handler2.act();
                this.sleep(9);
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            }
          }
        }
       
        public void setPrecio(int p)
        {
            this.precio=p;
        }       
        public double getPrecio()
        {
            return precio;
        }       
        public void setEuros(int e)
        {
            this.euros=e;
        }
        public double getEuros()
        {
            return euros;
        }
        public void setDetenido(boolean detenido) {
                this.detenido = detenido;
        }
        public void setPausado(boolean pausado) {
                this.pausado = pausado;
        }
        public void setCentesimas(int centesimas) {
                this.centesimas = centesimas;
        }
        public void setMinutos(int minutos) {
                this.minutos = minutos;
        }
        public void setSegundos(int segundos) {
                this.segundos = segundos;
        }
        public void setHoras(int horas) {
                this.horas = horas;
        }
}
Por último el Handler que se encarga de representar en el textView los valores. Es la unión entre la representación y el thread. Aunque tengo que buscar mas documentación para entenderlo mejor. Os dejo el Hand.java:

package Android.Com.Cronometro;

import android.os.Handler;
import android.os.Message;
import android.widget.TextView;


public class Hand extends Handler
{
        String hcron;
        TextView tiempo;
       
        public Hand(TextView t)
        {
                tiempo = t;
        }
        public void handleMessage(Message msg)
        {
                tiempo.setText(hcron);
        }
        public void setHcron(String hcron) {
                this.hcron = hcron;
        }
        public void act()
        {
                super.sendEmptyMessage(0);
        }
}
Espero que os sirva, iré completándolo conforme vaya avanzando con él.


LIBRO RECOMENDADO PARA APRENDER ANDROID

Uno de los libros fundamientales y que recomiendo para aprender Android y llegar a hacer aplicaciones profesionales es: Android 2 Application Developement de Reto Meier




2 comentarios :

  1. tengo una duda!! Cron donde ha sido declarado!!?? eso me marca como error!!

    ResponderEliminar