Cómo configurar un temporizador en Android

Respuestas:

143

La forma estándar de Java de usar temporizadores a través de java.util.Timer y java.util.TimerTask funciona bien en Android, pero debe tener en cuenta que este método crea un nuevo hilo.

Puede considerar utilizar la clase Handler muy conveniente (android.os.Handler) y enviar mensajes al controlador a través de sendMessageAtTime(android.os.Message, long)o sendMessageDelayed(android.os.Message, long). Una vez que reciba un mensaje, puede ejecutar las tareas deseadas. La segunda opción sería crear un objeto Runnable y programarlo mediante las funciones de Handler postAtTime(java.lang.Runnable, long)o postDelayed(java.lang.Runnable, long).

MannyNS
fuente
10
Esta es la forma incorrecta de hacer cosas en Android. En Android, desea utilizar el Administrador de alarmas (developer.android.com/reference/android/app/AlarmManager.html) para ejecutar tareas en el futuro.
Kurtis Nusbaum
9
@Kurtis Nusbaum La pregunta no dice qué tan lejos en el futuro está la tarea.
Christopher Perry
67
@KurtisNusbaum Eso no es necesariamente cierto, depende del contexto. Los documentos en AlarmManager dicen: "Nota: El Administrador de alarmas está destinado a casos en los que desea que se ejecute el código de su aplicación en un momento específico, incluso si su aplicación no se está ejecutando actualmente. Para operaciones de temporización normales (ticks, tiempos de espera, etc.) es más fácil y mucho más eficiente usar Handler ".
Christopher Perry
55
@ Scienceprodigy Ah, ya veo. Lo suficientemente justo.
Kurtis Nusbaum
10
el uso del método Handler para programar una tarea es confiable solo si la aplicación ha adquirido un wakeLock y, por lo tanto, está seguro de que el teléfono no entrará en estado de suspensión. Si el teléfono pasa al estado de suspensión, sendMessageDelayed y sendMessageAtTime no funcionarán. Por lo tanto, en ese escenario, AlarmManager sería una opción confiable.
crazyaboutliv
159

Sí, se puede usar el temporizador de Java , pero como la pregunta pide una mejor manera (para dispositivos móviles). Lo cual se explica aquí .


Por el bien de StackOverflow:

Como Timer crea un nuevo hilo, puede considerarse pesado,

si todo lo que necesita es conseguir es una llamada de vuelta, mientras que la actividad se está ejecutando un manejador puede ser usado en conjunción con una

Ejecutable :

private final int interval = 1000; // 1 Second
private Handler handler = new Handler();
private Runnable runnable = new Runnable(){
    public void run() {
        Toast.makeText(MyActivity.this, "C'Mom no hands!", Toast.LENGTH_SHORT).show();
    }
};
...
handler.postAtTime(runnable, System.currentTimeMillis()+interval);
handler.postDelayed(runnable, interval);

o un mensaje

private final int EVENT1 = 1; 
private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {         
        case Event1:
            Toast.makeText(MyActivity.this, "Event 1", Toast.LENGTH_SHORT).show();
            break;

        default:
            Toast.makeText(MyActivity.this, "Unhandled", Toast.LENGTH_SHORT).show();
            break;
        }
    }
};

...

Message msg = handler.obtainMessage(EVENT1);
handler.sendMessageAtTime(msg, System.currentTimeMillis()+interval);
handler.sendMessageDelayed(msg, interval);

en una nota al margen, este enfoque se puede usar, si desea ejecutar un fragmento de código en el hilo de la interfaz de usuario desde otro hilo.

si necesita que le devuelvan la llamada incluso si su actividad no se está ejecutando, puede usar un AlarmManager

Samuel
fuente
1
Oh sí, busqué en Google exactamente esta respuesta. Tome mi voto positivo por el enlace útil.
ulidtko
1
actualizado el enlace, habla sobre google teniendo problemas para mantener los enlaces.
Samuel
1
Este artículo de 2007 no dice que esté mal, pero siempre sospecho de un artículo móvil si tiene más de 3 años. Las cosas cambian bastante rápido.
StackOverflowed
1
sería más parecido a StackOverflow si pudiera citar los puntos principales de su enlace aquí en su respuesta.
n611x007
1
@naxa, mis dos centavos para hacer que esta respuesta se parezca más a StackOverflow.
Samuel
131

Como lo he visto, java.util.Timer es el más utilizado para implementar un temporizador.

Para una tarea repetitiva:

new Timer().scheduleAtFixedRate(task, after, interval);

Para una sola ejecución de una tarea:

new Timer().schedule(task, after);


la tarea es el método que se ejecutará
después del tiempo de ejecución inicial
( intervalo del tiempo para repetir la ejecución)

Thizzer
fuente
9
Solo agregaré que el tiempo es en milisegundos
Uri
2
documentos de desarrollo de Android para scheduleAtFixedRate
n611x007
1
taskpuede ser una instancia de su clase que hereda de java.util.TimerTask y reemplaza void run().
n611x007
2
Tantos votos a favor. Podrías hacer esto. Pero @Samuel describe la mejor manera. Vea su enlace "Lo que se explica aquí" para saber por qué. Además, no puedo actualizar la interfaz de usuario desde un hilo del temporizador. Y vea estas otras respuestas basadas en el controlador en otros hilos: (simple) stackoverflow.com/a/6702767/199364 , o (muestra varias alternativas) stackoverflow.com/a/4598737/199364
ToolmakerSteve
@quemeful porque no se trata siempre de conveniencia, se trata de la calidad y eficiencia del código. Esta forma de hacerlo utiliza más recursos que el
controlador
33

Espero que esto sea útil y que requiera menos esfuerzo implementarlo, clase Android CountDownTimer

p.ej

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();
Gaurav Adurkar
fuente
1
Esto es más fácil y golpea directamente en la cabeza para una cuenta regresiva simple como una hora de inicio de reproducción de video
Vijay Kumar Kanta
17

Probablemente Timerconcept

new CountDownTimer(40000, 1000) { //40000 milli seconds is total time, 1000 milli seconds is time interval

 public void onTick(long millisUntilFinished) {
  }
  public void onFinish() {
 }
}.start();

o

Método 2 ::

Programe el temporizador

Agregue una nueva variable de tiempo con nombre int. Configúrelo en 0. Agregue el siguiente código a la función onCreate en MainActivity.java.

//Declare the timer
Timer t = new Timer();
//Set the schedule function and rate
t.scheduleAtFixedRate(new TimerTask() {

    @Override
    public void run() {
        //Called each time when 1000 milliseconds (1 second) (the period parameter)
    }

},
//Set how long before to start calling the TimerTask (in milliseconds)
0,
//Set the amount of time between each execution (in milliseconds)
1000);

Ingrese al método de ejecución y agregue el siguiente código.

//We must use this function in order to change the text view text
runOnUiThread(new Runnable() {

    @Override
    public void run() {
        TextView tv = (TextView) findViewById(R.id.main_timer_text);
        tv.setText(String.valueOf(time));
        time += 1;
    }

});
vkulkarni
fuente
11

Es situacional.

La documentación de Android sugiere que debe usar AlarmManager para registrar una Intención que se disparará a la hora especificada si su aplicación no se está ejecutando.

De lo contrario, debe usar Handler.

Nota: El Administrador de alarmas está destinado a casos en los que desea ejecutar el código de su aplicación en un momento específico, incluso si su aplicación no se está ejecutando actualmente. Para operaciones de temporización normales (ticks, tiempos de espera, etc.) es más fácil y mucho más eficiente usar Handler.

Timothy Lee Russell
fuente
11

Aquí vamos. Necesitaremos dos clases. Estoy publicando un código que cambia el perfil de audio móvil después de cada 5 segundos (5000 mili segundos) ...

Nuestra 1ra clase

public class ChangeProfileActivityMain extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        Timer timer = new Timer();
        TimerTask updateProfile = new CustomTimerTask(ChangeProfileActivityMain.this);
        timer.scheduleAtFixedRate(updateProfile, 0, 5000);
    }

}

Nuestra 2da clase

public class CustomTimerTask extends TimerTask {

    private AudioManager audioManager;
    private Context context;
    private Handler mHandler = new Handler();

    // Write Custom Constructor to pass Context
    public CustomTimerTask(Context con) {
        this.context = con;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub

        // your code starts here.
        // I have used Thread and Handler as we can not show Toast without starting new thread when we are inside a thread.
        // As TimePicker has run() thread running., So We must show Toast through Handler.post in a new Thread. Thats how it works in Android..
        new Thread(new Runnable() {
            @Override
            public void run() {
                audioManager = (AudioManager) context.getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
                            Toast.makeText(context, "Ringer Mode set to Normal", Toast.LENGTH_SHORT).show();
                        } else {
                            audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
                            Toast.makeText(context, "Ringer Mode set to Silent", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        }).start();

    }

}
Rizwan Sohaib
fuente
5

Soy un novato en Android, pero aquí está la clase de temporizador que creé en base a las respuestas anteriores. Funciona para mi aplicación, pero agradezco cualquier sugerencia.

Ejemplo de uso:

...{
public Handler uiHandler = new Handler();

  private Runnable runMethod = new Runnable()
    {
        public void run()
        {
              // do something
        }
    };

    timer = new UITimer(handler, runMethod, timeoutSeconds*1000);       
        timer.start();
}...

public class UITimer
{
    private Handler handler;
    private Runnable runMethod;
    private int intervalMs;
    private boolean enabled = false;
    private boolean oneTime = false;

    public UITimer(Handler handler, Runnable runMethod, int intervalMs)
    {
        this.handler = handler;
        this.runMethod = runMethod;
        this.intervalMs = intervalMs;
    }

    public UITimer(Handler handler, Runnable runMethod, int intervalMs, boolean oneTime)
    {
        this(handler, runMethod, intervalMs);
        this.oneTime = oneTime;
    }

    public void start()
    {
        if (enabled)
            return;

        if (intervalMs < 1)
        {
            Log.e("timer start", "Invalid interval:" + intervalMs);
            return;
        }

        enabled = true;
        handler.postDelayed(timer_tick, intervalMs);        
    }

    public void stop()
    {
        if (!enabled)
            return;

        enabled = false;
        handler.removeCallbacks(runMethod);
        handler.removeCallbacks(timer_tick);
    }

    public boolean isEnabled()
    {
        return enabled;
    }

    private Runnable timer_tick = new Runnable()
    {
        public void run()
        {
            if (!enabled)
                return;

            handler.post(runMethod);

            if (oneTime)
            {
                enabled = false;
                return;
            }

            handler.postDelayed(timer_tick, intervalMs);
        }
    }; 
}
usuario868020
fuente
3

Estoy usando un controlador y ejecutable para crear un temporizador. Envuelvo esto en una clase abstracta. Simplemente deríbalo / impleméntalo y listo:

 public static abstract class SimpleTimer {
    abstract void onTimer();

    private Runnable runnableCode = null;
    private Handler handler = new Handler();

    void startDelayed(final int intervalMS, int delayMS) {
        runnableCode = new Runnable() {
            @Override
            public void run() {
                handler.postDelayed(runnableCode, intervalMS);
                onTimer();
            }
        };
        handler.postDelayed(runnableCode, delayMS);
    }

    void start(final int intervalMS) {
        startDelayed(intervalMS, 0);
    }

    void stop() {
        handler.removeCallbacks(runnableCode);
    }
}

Tenga en cuenta que handler.postDelayedse llama antes del código que se ejecutará; esto hará que el temporizador esté más cerrado como "esperado". Sin embargo, en los casos en que el temporizador se ejecuta con frecuencia y la tarea ( onTimer()) es larga, puede haber superposiciones. Si desea comenzar a contar intervalMSdespués de que la tarea haya terminado, mueva la onTimer()llamada una línea arriba.

elcuco
fuente
2

Creo que la forma de hacer esto en Android es que necesita un servicio en segundo plano para ejecutarse. En esa aplicación de fondo, cree el temporizador. Cuando el temporizador "marque" (establezca el intervalo de cuánto tiempo desea esperar), inicie la actividad que desea comenzar.

http://developer.android.com/guide/topics/fundamentals.html (<- este artículo explica la relación entre actividades, servicios, intenciones y otros fundamentos básicos del desarrollo de Android)

Crowe T. Robot
fuente
1

Solía ​​usar ( Timer, TimerTask) así como Handleriniciar tareas (que consumen mucho tiempo) periódicamente. Ahora he cambiado todo a RxJava. RxJava proporciona Observable.timercuál es más simple, menos propenso a errores y fácil de usar.

public class BetterTimerFragment extends Fragment {
  public static final String TAG = "BetterTimer";
  private TextView timeView;
  private Subscription timerSubscription;

  @Override
  public View onCreateView(LayoutInflater inflater,
                           @Nullable ViewGroup container,
                           @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_timer, container, false);
  }

  @Override
  public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    timeView = (TextView) view.findViewById(R.id.timeView);
  }

  @Override
  public void onResume() {
    super.onResume();

    // Right after the app is visible to users, delay 2 seconds
    // then kick off a (heavy) task every 10 seconds.
    timerSubscription = Observable.timer(2, 10, TimeUnit.SECONDS)
        .map(new Func1<Long, String>() {
          @Override
          public String call(Long unused) {
            // TODO: Probably do time-consuming work here.
            // This runs on a different thread than the main thread.
            return "Time: " + System.currentTimeMillis();
          }
        })
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<String>() {
          @Override
          public void call(String timeText) {
            // The result will then be propagated back to the main thread.
            timeView.setText(timeText);
          }
        }, new Action1<Throwable>() {
          @Override
          public void call(Throwable throwable) {
            Log.e(TAG, throwable.getMessage(), throwable);
          }
        });
  }

  @Override
  public void onPause() {
    super.onPause();

    // Don't kick off tasks when the app gets invisible.
    timerSubscription.unsubscribe();
  }
}
Thuy Trinh
fuente
1

Para la operación de temporización, debe usar Handler .

Si necesita ejecutar un servicio en segundo plano, AlarmManager es el camino a seguir.

robsf
fuente
0

este ejemplo inicia la unidad de temporizador destruida en Kotlin

private lateinit var timerTask: TimerTask

 timerTask = object : TimerTask() {
        override fun run() {
            Log.d("KTZ", "$minutes:$seconds");
            timeRecordingLiveData.postValue("$minutes:$seconds")
            seconds += 1;
            if (seconds == 60) {
                Log.d("KTZ", "$minutes:$seconds");
                timeRecordingLiveData.postValue("$minutes:$seconds")
                seconds = 0;
                minutes += 1;
            }
        }

    }

Cancele el horario en onDestroy ()

timerTask.cancel()
Kshitiz Mishra
fuente