¿Cómo configurar el temporizador en Android?


325

¿Alguien puede dar un ejemplo simple de actualizar un campo de texto cada segundo más o menos?

Quiero hacer una pelota voladora y necesito calcular / actualizar las coordenadas de la pelota cada segundo, por eso necesito algún tipo de temporizador.

No consigo nada de aquí .



Respuestas:


463

ok ya que esto no está aclarado todavía hay 3 formas simples de manejar esto. A continuación se muestra un ejemplo que muestra los 3 y en la parte inferior hay un ejemplo que muestra solo el método que creo que es preferible. También recuerde limpiar sus tareas en onPause, guardando el estado si es necesario.


import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Handler.Callback;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class main extends Activity {
    TextView text, text2, text3;
    long starttime = 0;
    //this  posts a message to the main thread from our timertask
    //and updates the textfield
   final Handler h = new Handler(new Callback() {

        @Override
        public boolean handleMessage(Message msg) {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text.setText(String.format("%d:%02d", minutes, seconds));
            return false;
        }
    });
   //runs without timer be reposting self
   Handler h2 = new Handler();
   Runnable run = new Runnable() {

        @Override
        public void run() {
           long millis = System.currentTimeMillis() - starttime;
           int seconds = (int) (millis / 1000);
           int minutes = seconds / 60;
           seconds     = seconds % 60;

           text3.setText(String.format("%d:%02d", minutes, seconds));

           h2.postDelayed(this, 500);
        }
    };

   //tells handler to send a message
   class firstTask extends TimerTask {

        @Override
        public void run() {
            h.sendEmptyMessage(0);
        }
   };

   //tells activity to run on ui thread
   class secondTask extends TimerTask {

        @Override
        public void run() {
            main.this.runOnUiThread(new Runnable() {

                @Override
                public void run() {
                   long millis = System.currentTimeMillis() - starttime;
                   int seconds = (int) (millis / 1000);
                   int minutes = seconds / 60;
                   seconds     = seconds % 60;

                   text2.setText(String.format("%d:%02d", minutes, seconds));
                }
            });
        }
   };


   Timer timer = new Timer();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        text = (TextView)findViewById(R.id.text);
        text2 = (TextView)findViewById(R.id.text2);
        text3 = (TextView)findViewById(R.id.text3);

        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button)v;
                if(b.getText().equals("stop")){
                    timer.cancel();
                    timer.purge();
                    h2.removeCallbacks(run);
                    b.setText("start");
                }else{
                    starttime = System.currentTimeMillis();
                    timer = new Timer();
                    timer.schedule(new firstTask(), 0,500);
                    timer.schedule(new secondTask(),  0,500);
                    h2.postDelayed(run, 0);
                    b.setText("stop");
                }
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        timer.cancel();
        timer.purge();
        h2.removeCallbacks(run);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }
}


Lo más importante que debe recordar es que la interfaz de usuario solo se puede modificar desde el hilo principal de la interfaz de usuario, por lo que debe usar un controlador o actividad.

Esto es lo que considero el método preferido.


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class TestActivity extends Activity {

    TextView timerTextView;
    long startTime = 0;

    //runs without a timer by reposting this handler at the end of the runnable
    Handler timerHandler = new Handler();
    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            long millis = System.currentTimeMillis() - startTime;
            int seconds = (int) (millis / 1000);
            int minutes = seconds / 60;
            seconds = seconds % 60;

            timerTextView.setText(String.format("%d:%02d", minutes, seconds));

            timerHandler.postDelayed(this, 500);
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        timerTextView = (TextView) findViewById(R.id.timerTextView);

        Button b = (Button) findViewById(R.id.button);
        b.setText("start");
        b.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Button b = (Button) v;
                if (b.getText().equals("stop")) {
                    timerHandler.removeCallbacks(timerRunnable);
                    b.setText("start");
                } else {
                    startTime = System.currentTimeMillis();
                    timerHandler.postDelayed(timerRunnable, 0);
                    b.setText("stop");
                }
            }
        });
    }

  @Override
    public void onPause() {
        super.onPause();
        timerHandler.removeCallbacks(timerRunnable);
        Button b = (Button)findViewById(R.id.button);
        b.setText("start");
    }

}



1
@ Dave.B, gracias por el gran ejemplo. ¿Hay alguna ventaja / desventaja de usar un método frente a los otros que ha descrito?
Gautam

2
@Gautam Creo que todos los métodos anteriores funcionan más o menos igual. Personalmente, prefiero el método de controlador descrito anteriormente con Runnable y h2 Handler, ya que es el que prescribe el sitio para desarrolladores de Android y, en mi opinión, también el más elegante.
Dave.B

66
Sería bueno tener su método preferido separado del resto del código. Como si pudieras tener un ejemplo que muestre tu forma preferida y otro que muestre las alternativas. Tener los tres métodos juntos hace que sea más difícil entender lo que está sucediendo (especialmente para un novato en Android como yo). Probablemente preguntando demasiado :)
Jesse Aldridge

44
@JesseAldridge Buena idea. Seguí adelante y agregué código solo con el método preferido.
Dave.B

1
@bluesm Sinceramente, no lo pensé, pero sí, eso funcionaría bien.
Dave.B

84

¡Es simple! Creas un nuevo temporizador.

Timer timer = new Timer();

Luego extiendes la tarea del temporizador

class UpdateBallTask extends TimerTask {
   Ball myBall;

   public void run() {
       //calculate the new position of myBall
   }
}

Y luego agregue la nueva tarea al temporizador con un intervalo de actualización

final int FPS = 40;
TimerTask updateBall = new UpdateBallTask();
timer.scheduleAtFixedRate(updateBall, 0, 1000/FPS);

Descargo de responsabilidad: esta no es la solución ideal. Esta es una solución que usa la clase Timer (como lo solicitó OP). En Android SDK, se recomienda utilizar la clase Handler (hay ejemplos en la respuesta aceptada).


1
si lees la publicación anterior, verás por qué esta no es una solución ideal
Dave.B

2
Por supuesto. El OP quería hacerlo con TimerTask, que no recomendaré usar en el juego.
ficción

3
¿Eh? El OP no especificó cómo querían que se hiciera. Se vincularon a un artículo que usaba TimerTask, pero no solicitaron que se hiciera de esa manera.
ToolmakerSteve

1
Ayudó mucho, gracias @fiction
Naveed Ahmad

1
Gran respuesta simple de seguir.
JMASTER B

64

Si también necesita ejecutar su código en el hilo de la interfaz de usuario (y no en el hilo del temporizador), eche un vistazo en el blog: http://steve.odyfamily.com/?p=12

public class myActivity extends Activity {
private Timer myTimer;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);

    myTimer = new Timer();
    myTimer.schedule(new TimerTask() {          
        @Override
        public void run() {
            TimerMethod();
        }

    }, 0, 1000);
}

private void TimerMethod()
{
    //This method is called directly by the timer
    //and runs in the same thread as the timer.

    //We call the method that will work with the UI
    //through the runOnUiThread method.
    this.runOnUiThread(Timer_Tick);
}


private Runnable Timer_Tick = new Runnable() {
    public void run() {

    //This method runs in the same thread as the UI.               

    //Do something to the UI thread here

    }
};
}

En aras de la integridad, tal vez podría mencionar qué hacer para detener el temporizador y quizás reiniciarlo. (Encontré la información necesaria aquí: stackoverflow.com/questions/11550561/… )
RenniePet

3
¿Hay alguna razón por la que no puedas llamar a runOnUIThread directamente desde el método de ejecución TimerTask? Parece funcionar bien y elimina otro nivel de anidamiento.
RichieHH

Claro, es solo un método didáctico para comprender todos los pasos. Sugiero que este estándar tenga un código legible.
Meir Gerenstadt

41

Si solo desea programar una cuenta regresiva hasta un momento en el futuro con notificaciones regulares en intervalos en el camino, puede usar la clase CountDownTimer que está disponible desde el nivel 1 de API.

new CountDownTimer(30000, 1000) {
    public void onTick(long millisUntilFinished) {
        editText.setText("Seconds remaining: " + millisUntilFinished / 1000);
    }

    public void onFinish() {
        editText.setText("Done");
    }
}.start();

2
CountDownTimer solo tiene sentido si sabes que quieres que desaparezca después de varias ejecuciones. Este no es un enfoque típico, ni particularmente flexible. Más común es el temporizador que se repite para siempre (que cancela cuando ya no es necesario), o el controlador que se ejecuta una vez, y luego se inicia de nuevo si será necesario nuevamente. Ver otras respuestas.
ToolmakerSteve

1
Tienes toda la razón. Desde el nombre de la clase, proporciona un tic-tac de temporizador de cuenta regresiva hasta el final y, por supuesto, utiliza Handler en su implementación.
Ahmed Hegazy

¿Cómo mostrar milisegundos también? En el formato SS:MiMi? Gracias
Ruchir Baronia

26

Este es un código simple para un temporizador:

Timer timer = new Timer();
TimerTask t = new TimerTask() {       
    @Override
    public void run() {

        System.out.println("1");
    }
};
timer.scheduleAtFixedRate(t,1000,1000);

12

Creo que puedes hacerlo de forma Rx como:

 timerSubscribe = Observable.interval(1, TimeUnit.SECONDS)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Long>() {
                @Override
                public void call(Long aLong) {
                      //TODO do your stuff
                }
            });

Y cancela esto como:

timerSubscribe.unsubscribe();

Rx Timer http://reactivex.io/documentation/operators/timer.html


10

Debido a que esta pregunta sigue atrayendo a muchos usuarios de la búsqueda de Google (sobre el temporizador de Android), me gustaría insertar mis dos monedas.

En primer lugar, la clase Timer quedará obsoleta en Java 9 (lea la respuesta aceptada) .

La forma oficial sugerida es utilizar ScheduledThreadPoolExecutor, que es más efectivo y rico en funciones que, además, puede programar comandos para que se ejecuten después de un retraso determinado o para ejecutarse periódicamente. Además, brinda flexibilidad y capacidades adicionales de ThreadPoolExecutor.

Aquí hay un ejemplo del uso de funcionalidades simples.

  1. Crear servicio de ejecutor:

    final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
  2. Solo programe su carrera:

    final Future<?> future = SCHEDULER.schedule(Runnable task, long delay,TimeUnit unit);
  3. Ahora puede usar futurepara cancelar la tarea o verificar si se hace, por ejemplo:

    future.isDone();

Espero que encuentres esto útil para crear tareas en Android.

Ejemplo completo:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Future<?> sampleFutureTimer = scheduler.schedule(new Runnable(), 120, TimeUnit.SECONDS);
if (sampleFutureTimer.isDone()){
    // Do something which will save world.
}

8

Me sorprende que no haya una respuesta que mencione la solución con RxJava2 . Es realmente simple y proporciona una manera fácil de configurar el temporizador en Android.

Primero debe configurar la dependencia de Gradle, si aún no lo hizo:

implementation "io.reactivex.rxjava2:rxjava:2.x.y"

(reemplazar xy ycon el número de versión actual )

Como solo tenemos una TAREA simple, NO REPETITIVA , podemos usar Completableobject:

Completable.timer(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(() -> {
            // Timer finished, do something...
        });

Para REPETIR TAREA , puede usar Observablede una manera similar:

Observable.interval(2, TimeUnit.SECONDS, Schedulers.computation())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(tick -> {
            // called every 2 seconds, do something...
        }, throwable -> {
            // handle error
        });

Schedulers.computation()garantiza que nuestro temporizador se ejecute en el subproceso de fondo y .observeOn(AndroidSchedulers.mainThread())significa que el código que ejecutamos después de que el temporizador finalice se realizará en el subproceso principal.

Para evitar pérdidas de memoria no deseadas, debe asegurarse de darse de baja cuando se destruya Actividad / Fragmento.


44
Este es el enfoque más limpio!
Constantin

¿Cómo se cancelan estos? es decir, cuando el usuario presiona el botón [STOP] en ​​la IU y el Completable se cancela antes de ejecutarlo.
Alguien en algún lugar

@SomeoneSomewhere Simplemente guarde el método Subscriptiondevuelto .subscribe()en la variable y luego llame subscription.unsubscribe()cuando desee detener el temporizador.
Micer

2

Él es una solución más simple, funciona bien en mi aplicación.

  public class MyActivity extends Acitivity {

    TextView myTextView;
    boolean someCondition=true;

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_activity);

            myTextView = (TextView) findViewById(R.id.refreshing_field);

            //starting our task which update textview every 1000 ms
            new RefreshTask().execute();



        }

    //class which updates our textview every second

    class RefreshTask extends AsyncTask {

            @Override
            protected void onProgressUpdate(Object... values) {
                super.onProgressUpdate(values);
                String text = String.valueOf(System.currentTimeMillis());
                myTextView.setText(text);

            }

            @Override
            protected Object doInBackground(Object... params) {
                while(someCondition) {
                    try {
                        //sleep for 1s in background...
                        Thread.sleep(1000);
                        //and update textview in ui thread
                        publishProgress();
                    } catch (InterruptedException e) {
                        e.printStackTrace(); 

                };
                return null;
            }
        }
    }

2

Desea que las actualizaciones de su interfaz de usuario sucedan en el hilo de interfaz de usuario ya existente.

La mejor manera es usar un controlador que use postDelayed para ejecutar un Runnable después de un retraso (cada ejecución programa la siguiente); borre la devolución de llamada con removeCallbacks.

Ya está buscando en el lugar correcto, así que mírelo nuevamente, quizás aclare por qué esa muestra de código no es lo que desea. (Consulte también el artículo idéntico en Actualización de la IU desde un temporizador ).


Desafortunadamente, tu enlace está muerto. No puedo encontrar rápidamente el artículo correcto.
Lekensteyn el


1

Aquí hay una manera simple y confiable ...

Ponga el siguiente código en su Actividad, y el método tick () se llamará cada segundo en el hilo de la interfaz de usuario mientras su actividad está en el estado "reanudado". Por supuesto, puede cambiar el método tick () para hacer lo que quiera o para que lo llamen con mayor o menor frecuencia.

@Override
public void onPause() {
    _handler = null;
    super.onPause();
}

private Handler _handler;

@Override
public void onResume() {
    super.onResume();
    _handler = new Handler();
    Runnable r = new Runnable() {
        public void run() {
            if (_handler == _h0) {
                tick();
                _handler.postDelayed(this, 1000);
            }
        }

        private final Handler _h0 = _handler;
    };
    r.run();
}

private void tick() {
    System.out.println("Tick " + System.currentTimeMillis());
}

Para aquellos interesados, el código "_h0 = _handler" es necesario para evitar que dos temporizadores se ejecuten simultáneamente si su actividad se detiene y se reanuda dentro del período de tick.


2
¿Por qué hacer esto torpe _h0enfoque, en lugar de removeCallbacksen onPause, como todos los demás?
ToolmakerSteve

1

También puedes usar un animador para ello:

int secondsToRun = 999;

ValueAnimator timer = ValueAnimator.ofInt(secondsToRun);
timer.setDuration(secondsToRun * 1000).setInterpolator(new LinearInterpolator());
timer.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
    {
        @Override
        public void onAnimationUpdate(ValueAnimator animation)
        {
            int elapsedSeconds = (int) animation.getAnimatedValue();
            int minutes = elapsedSeconds / 60;
            int seconds = elapsedSeconds % 60;

            textView.setText(String.format("%d:%02d", minutes, seconds));
        }
    });
timer.start();

0

Necesita crear un hilo para manejar el ciclo de actualización y usarlo para actualizar el área de texto. Sin embargo, la parte difícil es que solo el hilo principal puede modificar la interfaz de usuario, por lo que el hilo del bucle de actualización debe indicarle al hilo principal que realice la actualización. Esto se hace usando un controlador.

Consulte este enlace: http://developer.android.com/guide/topics/ui/dialogs.html# Haga clic en la sección titulada "Ejemplo de Diálogo de progreso con un segundo hilo". Es un ejemplo de exactamente lo que debe hacer, excepto con un cuadro de diálogo de progreso en lugar de un campo de texto.


No hagas esto. Hay una clase de temporizador simple que hace todo esto por usted. Y esta pregunta no tiene nada que ver con diálogos de progreso o diálogos en absoluto.
Falmarri

¿Viste la sección del enlace que publiqué o acabas de ver la palabra diálogo y asumir? El código allí es 100% relevante. También para su información, si usa el temporizador, todavía está creando un hilo para manejar el ciclo de actualización. Aún necesitará usar el controlador como se describe en el enlace que publiqué.
Nick

Desafortunadamente, la página vinculada ya no contiene una sección con el título mencionado. Al vincular al código, siempre se debe incluir el fragmento de clave directamente en su respuesta.
ToolmakerSteve

0
void method(boolean u,int max)
{
    uu=u;
    maxi=max;
    if (uu==true)
    { 
        CountDownTimer uy = new CountDownTimer(maxi, 1000) 
  {
            public void onFinish()
            {
                text.setText("Finish"); 
            }

            @Override
            public void onTick(long l) {
                String currentTimeString=DateFormat.getTimeInstance().format(new Date());
                text.setText(currentTimeString);
            }
        }.start();
    }

    else{text.setText("Stop ");
}

2
Tal vez algunas sangrías de código y explicaciones de código serían útiles.
Raul Rene

0

Si alguien está interesado, comencé a jugar creando un objeto estándar para ejecutarlo en un hilo de la interfaz de usuario de actividades. Parece funcionar bien. Comentarios bienvenidos Me encantaría que esté disponible en el diseñador de diseño como un componente para arrastrar a una Actividad. No puedo creer que algo así ya no exista.

package com.example.util.timer;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;

public class ActivityTimer {

    private Activity m_Activity;
    private boolean m_Enabled;
    private Timer m_Timer;
    private long m_Delay;
    private long m_Period;
    private ActivityTimerListener m_Listener;
    private ActivityTimer _self;
    private boolean m_FireOnce;

    public ActivityTimer() {
        m_Delay = 0;
        m_Period = 100;
        m_Listener = null;
        m_FireOnce = false;
        _self = this;
    }

    public boolean isEnabled() {
        return m_Enabled;
    }

    public void setEnabled(boolean enabled) {
        if (m_Enabled == enabled)
            return;

        // Disable any existing timer before we enable a new one
        Disable();

        if (enabled) {
            Enable();
        }
    }

    private void Enable() {
        if (m_Enabled)
            return;

        m_Enabled = true;

        m_Timer = new Timer();
        if (m_FireOnce) {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay);
        } else {
            m_Timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    OnTick();
                }
            }, m_Delay, m_Period);
        }
    }

    private void Disable() {
        if (!m_Enabled)
            return;

        m_Enabled = false;

        if (m_Timer == null)
            return;

        m_Timer.cancel();
        m_Timer.purge();
        m_Timer = null;
    }

    private void OnTick() {
        if (m_Activity != null && m_Listener != null) {
            m_Activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    m_Listener.OnTimerTick(m_Activity, _self);
                }
            });
        }
        if (m_FireOnce)
            Disable();
    }

    public long getDelay() {
        return m_Delay;
    }

    public void setDelay(long delay) {
        m_Delay = delay;
    }

    public long getPeriod() {
        return m_Period;
    }

    public void setPeriod(long period) {
        if (m_Period == period)
            return;
        m_Period = period;
    }

    public Activity getActivity() {
        return m_Activity;
    }

    public void setActivity(Activity activity) {
        if (m_Activity == activity)
            return;
        m_Activity = activity;
    }

    public ActivityTimerListener getActionListener() {
        return m_Listener;
    }

    public void setActionListener(ActivityTimerListener listener) {
        m_Listener = listener;
    }

    public void start() {
        if (m_Enabled)
            return;
        Enable();
    }

    public boolean isFireOnlyOnce() {
        return m_FireOnce;
    }

    public void setFireOnlyOnce(boolean fireOnce) {
        m_FireOnce = fireOnce;
    }
}

En la actividad, tengo este onStart:

@Override
protected void onStart() {
    super.onStart();

    m_Timer = new ActivityTimer();
    m_Timer.setFireOnlyOnce(true);
    m_Timer.setActivity(this);
    m_Timer.setActionListener(this);
    m_Timer.setDelay(3000);
    m_Timer.start();
}

1
amigo, ¿qué tiene de malo el ActivityTimerListener? Mi paquete ADT dijo que no existe tal clase.
Sorokin Andrey

0
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.app.Activity;

public class MainActivity extends Activity {

 CheckBox optSingleShot;
 Button btnStart, btnCancel;
 TextView textCounter;

 Timer timer;
 MyTimerTask myTimerTask;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  optSingleShot = (CheckBox)findViewById(R.id.singleshot);
  btnStart = (Button)findViewById(R.id.start);
  btnCancel = (Button)findViewById(R.id.cancel);
  textCounter = (TextView)findViewById(R.id.counter);

  btnStart.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View arg0) {

    if(timer != null){
     timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
     //singleshot delay 1000 ms
     timer.schedule(myTimerTask, 1000);
    }else{
     //delay 1000ms, repeat in 5000ms
     timer.schedule(myTimerTask, 1000, 5000);
    }
   }});

  btnCancel.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if (timer!=null){
     timer.cancel();
     timer = null;
    }
   }
  });

 }

 class MyTimerTask extends TimerTask {

  @Override
  public void run() {
   Calendar calendar = Calendar.getInstance();
   SimpleDateFormat simpleDateFormat = 
     new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
   final String strDate = simpleDateFormat.format(calendar.getTime());

   runOnUiThread(new Runnable(){

    @Override
    public void run() {
     textCounter.setText(strDate);
    }});
  }

 }

}

.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity" >

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:autoLink="web"
    android:text="http://android-er.blogspot.com/"
    android:textStyle="bold" />
<CheckBox 
    android:id="@+id/singleshot"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Single Shot"/>


Veo que has agregado esto varios años después de la pregunta y las respuestas originales. Agregue una explicación de cómo esta respuesta se compara con otras respuestas que ya estaban allí. ¿Por qué agregaste otro? ¿Qué beneficio / cuándo útil / qué deficiencia viste en otras respuestas?
ToolmakerSteve

Solo comparto un código que está haciendo el mismo trabajo con un enfoque diferente. Pero cada vez que desee actualizar los datos de cualquier vista. Debes usar handler para ello. porque muchas veces he notado que el uso de un timertask para actualizar una vista no funciona ... El método @ Dave.B es más correcto que yo sepa.
Zar E Ahmer

0

Si ya tienes tiempo delta.

public class Timer {
    private float lastFrameChanged;
    private float frameDuration;
    private Runnable r;

    public Timer(float frameDuration, Runnable r) {
        this.frameDuration = frameDuration;
        this.lastFrameChanged = 0;
        this.r = r;
    }

    public void update(float dt) {
        lastFrameChanged += dt;

        if (lastFrameChanged > frameDuration) {
            lastFrameChanged = 0;
            r.run();
        }
    }
}

0

I Abstract Timer y lo convertí en una clase separada:

Timer.java

import android.os.Handler;

public class Timer {

    IAction action;
    Handler timerHandler = new Handler();
    int delayMS = 1000;

    public Timer(IAction action, int delayMS) {
        this.action = action;
        this.delayMS = delayMS;
    }

    public Timer(IAction action) {
        this(action, 1000);
    }

    public Timer() {
        this(null);
    }

    Runnable timerRunnable = new Runnable() {

        @Override
        public void run() {
            if (action != null)
                action.Task();
            timerHandler.postDelayed(this, delayMS);
        }
    };

    public void start() {
        timerHandler.postDelayed(timerRunnable, 0);
    }

    public void stop() {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

Y extraer la acción principal de la Timerclase como

IAction.java

public interface IAction {
    void Task();
}

Y lo usé así:

MainActivity.java

public class MainActivity extends Activity implements IAction{
...
Timer timerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
        ...
        timerClass = new Timer(this,1000);
        timerClass.start();
        ...
}
...
int i = 1;
@Override
public void Task() {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            timer.setText(i + "");
            i++;
        }
    });
}
...
}

Espero que esto ayude 😊👌


0

Yo uso de esta manera:

String[] array={
       "man","for","think"
}; int j;

luego debajo de onCreate

TextView t = findViewById(R.id.textView);

    new CountDownTimer(5000,1000) {

        @Override
        public void onTick(long millisUntilFinished) {}

        @Override
        public void onFinish() {
            t.setText("I "+array[j] +" You");
            j++;
            if(j== array.length-1) j=0;
            start();
        }
    }.start();

Es una manera fácil de resolver este problema.


0

Para aquellos que no pueden confiar en Chronometer , hice una clase de utilidad con una de las sugerencias:

public class TimerTextHelper implements Runnable {
   private final Handler handler = new Handler();
   private final TextView textView;
   private volatile long startTime;
   private volatile long elapsedTime;

   public TimerTextHelper(TextView textView) {
       this.textView = textView;
   }

   @Override
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds = seconds % 60;

       textView.setText(String.format("%d:%02d", minutes, seconds));

       if (elapsedTime == -1) {
           handler.postDelayed(this, 500);
       }
   }

   public void start() {
       this.startTime = System.currentTimeMillis();
       this.elapsedTime = -1;
       handler.post(this);
   }

   public void stop() {
       this.elapsedTime = System.currentTimeMillis() - startTime;
       handler.removeCallbacks(this);
   }

   public long getElapsedTime() {
       return elapsedTime;
   }
 }

para usar ... solo haz:

 TimerTextHelper timerTextHelper = new TimerTextHelper(textView);
 timerTextHelper.start();

.....

 timerTextHelper.stop();
 long elapsedTime = timerTextHelper.getElapsedTime();
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.