Foro de elhacker.net

Programación => Java => Mensaje iniciado por: PabloPbl en 12 Abril 2015, 05:41 am



Título: [Ayuda]Timer en Android
Publicado por: PabloPbl en 12 Abril 2015, 05:41 am
Pues cuando yo trabajaba en Java puro, recuerdo que usaba muchísimo la clase Timer la cual sirve para hacer correr procesos particulares o en diferentes hilos.

Pues ahora eso mismo me gustaría hacerlo en Android, me he fijado la Api de Android y si esta disponible la misma, solo que Android la ha cambiado bastante y lo encuentro un tanto complicado, nada que ver como lo hacia en Java.

He buscado por la red y he encontrado bastante material, por ejemplo este y otros:
http://stackoverflow.com/questions/4597690/android-timer-how (http://stackoverflow.com/questions/4597690/android-timer-how)
Trato de entenderlo, pero me es complicado, ¿alguien me podría ayudar a entender un poco de esto?

Se que hay otras formas como los Services, pero es demasiado para lo que requiero, necesito algo sencillo, por eso elige este, si alguien conoce alguna clase mejor, que la diga.


Título: Re: [Ayuda]Timer en Android
Publicado por: Usuario Invitado en 12 Abril 2015, 16:10 pm
Utiliza Calendar de Java, que creo está disponible en el kit de Android. Es fácil de manejar.


Saludos.


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 12 Abril 2015, 16:59 pm
Calendar sirve para hacer acciones en otro hilo?, tengo entendido que sirve para obtener la fecha y la hora, me acabo de fijar en la API de Android y pues si, esta ahí.

Salu2


Título: Re: [Ayuda]Timer en Android
Publicado por: Usuario Invitado en 12 Abril 2015, 17:10 pm
Ya veo, tu me hablas de concurrencia. ¿Existe alguna diferencia notoria entre Timer de Java y Android?

Es decir, en Android es tan diferente hacer ésto:

Código
  1. class SomeTask extends TimerTask {
  2.    @Override
  3.    public void run() {
  4.      System.out.println("Time's up!");
  5.    }
  6. }

Código
  1. public class Main {
  2.    private Timer timer;
  3.  
  4.    public void initialize() {
  5.        timer = new Timer();
  6.        timer.schedule(new SomeTask(), 1000, 5000); // inicia en 1 segundo y se repite cada 5
  7.    }
  8.    public void cancel() {
  9.        if(timer != null) {
  10.            timer.cancel();
  11.            timer = null;
  12.        }
  13.    }
  14. }


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 12 Abril 2015, 17:28 pm
Haber si entiendo, estas creando una clase que hereda de TimerTask y sobrescribes su método run, que es el que se va a ejecutar cada cierto tiempo.

Y desde otra clase, creas un Timer:
Código
  1. timer = new Timer();

Y con esto especificas que acción se va a ejecutar cada cierto tiempo,  la cual es la clase TimerTask y tiene 2 parámetros más, en el primero se especifica cuando iniciara, y el segundo especificas cada cuanto se va a ejecutar la acción.
Código
  1. timer.schedule(new SomeTask(), 1000, 5000); // inicia en 1 segundo y se repite cada 5

En resumen este código mostraría Time's up! en pantalla cada 5 segundos?


Título: Re: [Ayuda]Timer en Android
Publicado por: Usuario Invitado en 12 Abril 2015, 18:18 pm
Exactamente. El primer parámetro de schedule indica el timeout, es decir, la cuenta regresiva para que se inicie por primera véz la tarea, y el segundo parámetro el intérvalo entre ejecuciones. Ésto es ideal cuando se quiere mostrar avisos cada X tiempo, por ejemplo.


Un saludo.


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 12 Abril 2015, 19:18 pm
Perfecto, muchas gracias Gus  ;D, he hecho pruebas y funciona de maravilla, pero hasta cierto punto.

La primera prueba la hice de la siguiente manera:

Código
  1. public class Prueba extends ActionBarActivity {
  2.    @Override
  3.    protected void onCreate(Bundle savedInstanceState) {
  4.        super.onCreate(savedInstanceState);
  5.        setContentView(R.layout.activity_1);
  6.  
  7.        Timer timer = new Timer();
  8.        timer.schedule(new classProcess(),1000, 1000);
  9.    }
  10.  
  11.    class classProcess extends TimerTask{
  12.  
  13.    public void run() {
  14.        Log.e("HILO CORRIENDO", "HILO CORRIENDO");
  15.    }
  16.    }
  17. }
  18.  

Pues el código de arriba funciona perfecto, he utilizado un clase interna(sabia que alguna día me iba a ser útil) que extiende de TimerTask y sobreescribo el método run y pongo que se mostrara un Log en la consola. Todo esto se ejecutara desde el Timer, que lo cree en el método onCreate, le paso como parámetro una instancia de la clase interna "classProcess", iniciara en 1 segundo y se repetirá cada 5 segundos, esto lo hace de lujo.

Pero cuando quiero, modificar el valor de un TextView cada cierto tiempo, en este caso cada segundo, me arroja un error en el emulador. El código lo he hecho de 2 formas, pero ninguna me anda.

Antes de mostrar el código, quería comentarles lo que quiero hacer. Lo que quiero lograr es que un textView cambie su valor cada segundo, osea funciona como un temporizador. Por defecto le pongo un texto que dice 30 segundos,  y bueno con la ayuda de Timer quiero hacer que el TextView vaya bajando cada segundo hasta llegar a 0 y ahí detenerse.

Esta es la primera forma, he puesto un par de comentarios en el código para que se entienda más el mismo:
Código
  1. public class Prueba extends ActionBarActivity {
  2.  
  3.    private TextView tv;
  4.  
  5.    @Override
  6.    protected void onCreate(Bundle savedInstanceState) {
  7.        super.onCreate(savedInstanceState);
  8.        setContentView(R.layout.activity_1);
  9.  
  10.        tv = (TextView)findViewById(R.id.tvTemporizador);
  11.  
  12.        Timer timer = new Timer();
  13.        timer.schedule(new classProcess(),1000, 1000);
  14.    }
  15.  
  16.    class classProcess extends TimerTask{
  17.  
  18.        public void run() {
  19.            int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;//Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  20.            tv.setText(String.valueOf(bajar1Segundo));//Cambio el valor del TextView
  21.  
  22.            if(bajar1Segundo == 0) {
  23.                timer.cancel();//No se si este método parara el Timer, No llegue a comprobar, ya que no llega a hasta este punto, ya que apenas inicia el programa se traba al querer cambiar los valores de los TextView
  24.                Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  25.            }
  26.        }
  27.    }
  28. }
  29.  
En el código de arriba, creo que el error estaba en que: desde la clase interna quería acceder a las variables de clase que son privadas, de la clase principal, ustedes me dirán, ¿Por que no te diste cuenta de esto antes? pues es la primera vez que lo hago así, aparte el IDE no me arrojaba error, no me marcaba con lineas roja ni nada, y es por eso que he intentado también de esta forma:

Código
  1. public class Prueba extends ActionBarActivity {
  2.  
  3.    private TextView tv;
  4.  
  5.    @Override
  6.    protected void onCreate(Bundle savedInstanceState) {
  7.        super.onCreate(savedInstanceState);
  8.        setContentView(R.layout.activity_1);
  9.  
  10.        tv = (TextView)findViewById(R.id.tvTemporizador);
  11.  
  12.        Timer timer = new Timer();
  13.        timer.schedule(new ClassProcess(this.tv),1000, 1000);
  14.    }
  15.  
  16.    class ClassProcess extends TimerTask{
  17.        private TextView tv;
  18.  
  19.        public classProcess(TextView tv) {
  20.            this.tv = tv;
  21.        }
  22.  
  23.        public void run() {
  24.            int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;//Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  25.            tv.setText(String.valueOf(bajar1Segundo));//Cambio el valor del TextView
  26.  
  27.            if(bajar1Segundo == 0) {
  28.                Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  29.            }
  30.        }
  31.    }
  32. }
  33.  

Pues la diferencia entre el código que esta arriba y el que esta arriba de este de arriba(ya saben xD), es que la clase interna recibe parámetros en su constructor, recibe un TextView. Entonces en vez en vez de interactuar directamente con el TextView de la clase principal, interactuo con el TextView que recibo por parámetro de la clase principal, pero también me da error, y no se que puede ser.

Si no entienden algo, díganmelo.

Salu2


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 12 Abril 2015, 22:08 pm
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Ese error, creo que me esta diciendo que solo puedo modificar las Views(Elementos visuales) desde el Thread original y no desde otro Hilo.

¿Que alguien me diga si esto es cierto?


Título: Re: [Ayuda]Timer en Android
Publicado por: Usuario Invitado en 12 Abril 2015, 23:17 pm
Así es. Tienes que obtener el thread en donde está corriendo el Activity. Intenta:

Código
  1. getActivity().runOnUiThread(new Runnable() {
  2.    @Override
  3.    public void run() {
  4.        //Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  5.        int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;
  6.        tv.setText(String.valueOf(bajar1Segundo)); //Cambio el valor del TextView
  7.        if(bajar1Segundo == 0) {
  8.            Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  9.        };
  10.    }
  11. });

El código anterior debe ir dentro del run de ClassProcess.


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 13 Abril 2015, 16:29 pm
Pongo el código dentro del run de la clase interna, pero me da error en esta linea, creo que no reconoce el método getActivity()

Código
  1. getActivity().runOnUiThread(new Runnable() {

También he intentado de esta forma, pero también me da error:

Código
  1. getApplication().runOnUiThread(new Runnable() {


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 13 Abril 2015, 16:30 pm
La clase interna me quedo de esta forma:

Código
  1. class TimerTask2 extends java.util.TimerTask{
  2.        public void run() {
  3.            getActivity().runOnUiThread(new Runnable() {
  4.                @Override
  5.                public void run() {
  6.                    //Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  7.                    int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;
  8.                    tv.setText(String.valueOf(bajar1Segundo)); //Cambio el valor del TextView
  9.                    if(bajar1Segundo == 0) {
  10.                        Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  11.                    };
  12.                }
  13.            });
  14.        }
  15.    }


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 13 Abril 2015, 16:46 pm
Gus eres grande, muchas gracias por toda la ayuda  ;D.

Puse el mismo código, pero sin poner el método getActivity() y funciona de maravilla la App, osea el code me quedo algo así:

Código
  1. public void run() {
  2.            runOnUiThread(new Runnable() {
  3.                @Override
  4.                public void run() {
  5.                    //Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  6.                    int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;
  7.                    tv.setText(String.valueOf(bajar1Segundo)); //Cambio el valor del TextView
  8.                    if(bajar1Segundo == 0) {
  9.                        Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  10.                    };
  11.                }
  12.            });
  13.        }

Saludos crack!!!


Título: Re: [Ayuda]Timer en Android
Publicado por: Usuario Invitado en 13 Abril 2015, 17:48 pm
getActivity(), te devuelve la actividad. También bastaría con Prueba.this. Intenta hacerlo con un callback en lugar de una clase:

Código
  1. public class Prueba extends ActionBarActivity {
  2.  
  3.    private TextView tv;
  4.    private Timer timer;
  5.    private TimerTask timerTask;
  6.  
  7.    @Override
  8.    protected void onCreate(Bundle savedInstanceState) {
  9.        super.onCreate(savedInstanceState);
  10.        setContentView(R.layout.activity_1);
  11.        tv = (TextView)findViewById(R.id.tvTemporizador);
  12.    }
  13.    public void startTimer() {
  14.        timer = new Timer();
  15.        initializeTimerTask();
  16.        timer.schedule(new TimerTask,1000, 1000);
  17.    }
  18.    private void initializeTimerTask() {
  19.        timerTask = new TimerTask() {
  20.            @Override
  21.            public void run() {
  22.                getActivity().runOnUiThread(new Runnable() {
  23.                @Override
  24.                public void run() {
  25.                    //Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  26.                    int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;
  27.                    tv.setText(String.valueOf(bajar1Segundo)); //Cambio el valor del TextView
  28.                    if(bajar1Segundo == 0) {
  29.                        Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  30.                    };
  31.                }
  32.            });
  33.    }
  34.    public void cancelTimer() {
  35.        if (timer != null) {
  36.            timer.cancel();
  37.            timer = null;
  38.        }
  39.    }
  40. }


Saludos.


PD: Ya vi que lo solucionaste xD.


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 13 Abril 2015, 19:09 pm
Call back? nunca había oído de eso. He mirado el código que me haz pasado y hay cosas que nunca había visto, por lo que veo cuando tu haces:
Código
  1. timer.schedule(new TimerTask,1000, 1000);
Como primer parámetro le estas pasando un nuevo objeto, pero como se yo que se va a ejecutar este código:
Código
  1. private void initializeTimerTask() {
  2.        timerTask = new TimerTask() {
  3.            @Override
  4.            public void run() {
  5.                getActivity().runOnUiThread(new Runnable() {
  6.                @Override
  7.                public void run() {
  8.                    //Obtengo el valor y lo bajo 1, por ejemplo, si es 30 ahora sera 29
  9.                    int bajar1Segundo = Integer.parseInt(tv.getText().toString())-1;
  10.                    tv.setText(String.valueOf(bajar1Segundo)); //Cambio el valor del TextView
  11.                    if(bajar1Segundo == 0) {
  12.                        Toast.makeText(getApplicationContext(), "El tiempo se ha terminado", Toast.LENGTH_LONG);
  13.                    };
  14.                }
  15.            });
  16.    }
  17.  

Jajaja xDDD, justo me acabo de dar cuenta de algo, capaz que lo que haz querido hacer, es esto:
Código
  1. timer.schedule(timerTask,1000, 1000);
En vez de pasarle un nuevo objeto, le pasamos el que creamos anteriormente.

Creo que es mas fácil hacerlo así no?

PD: Acabo de leer el principio de este mensaje y me mato xDDD


Título: Re: [Ayuda]Timer en Android
Publicado por: Usuario Invitado en 13 Abril 2015, 19:49 pm
Sí, debes pasarle el objeto que está como propiedad y que se ha inicializado en el método initializeTimerTask(), lo que pasa es que en la edición olvidé cambiar eso xD.


Saludos.


Título: Re: [Ayuda]Timer en Android
Publicado por: PabloPbl en 13 Abril 2015, 21:38 pm
Ahora si tiene mas sentido jaja.

Gracias y un Saludo!!