Como definir um timer no android

172

Qual é a maneira correta de definir um timer no android para iniciar uma tarefa (uma função que eu criei que não altera a interface do usuário)? Use isso da maneira Java: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Timer.html

Ou existe uma maneira melhor no android (manipulador do android)?

n179911
fonte

Respostas:

143

A maneira Java padrão de usar temporizadores via java.util.Timer e java.util.TimerTask funciona bem no Android, mas você deve estar ciente de que esse método cria um novo encadeamento.

Você pode considerar usar a classe Handler, muito conveniente (android.os.Handler), e enviar mensagens para o manipulador por meio de sendMessageAtTime(android.os.Message, long)ou sendMessageDelayed(android.os.Message, long). Depois de receber uma mensagem, você pode executar as tarefas desejadas. A segunda opção seria criar um objeto Runnable e agendá-lo através das funções do Handler postAtTime(java.lang.Runnable, long)ou postDelayed(java.lang.Runnable, long).

MannyNS
fonte
10
Esta é a maneira errada de fazer as coisas no android. No Android, você deseja usar o Gerenciador de alarmes (developer.android.com/reference/android/app/AlarmManager.html) para executar tarefas no futuro.
Kurtis Nusbaum 15/10
9
@ Kurtis Nusbaum A questão não diz até que ponto a tarefa está no futuro.
Christopher Perry
67
@KurtisNusbaum Isso não é necessariamente verdade, depende do contexto. Os documentos do AlarmManager dizem: "Observação: o Gerenciador de alarmes destina-se aos casos em que você deseja que o código do seu aplicativo seja executado em um horário específico, mesmo se o aplicativo não estiver em execução no momento. Para operações normais de tempo (marcações, tempos limites, etc.) é mais fácil e muito mais eficiente usar o Handler ".
9309 Christopher Christopher
5
@Scienceprodigy Ah, entendo. Justo.
precisa saber é o seguinte
10
o uso do método Handler de agendamento de uma tarefa é confiável apenas se o aplicativo adquiriu um wakeLock e, portanto, você tem certeza de que o telefone não entrará no estado de suspensão. Se o telefone entrar no estado de suspensão, o sendMessageDelayed e o sendMessageAtTime não funcionarão. Portanto, nesse cenário, o AlarmManager seria uma escolha confiável.
2771212
159

sim, o timer do java pode ser usado , mas como a pergunta pede um caminho melhor (para celular). O que é explicado aqui .


Para o StackOverflow:

Como o Timer cria um novo segmento, ele pode ser considerado pesado,

se tudo o que você precisa é receber uma chamada de retorno enquanto a atividade está em execução, um Handler pode ser usado em conjunto com um

Executável :

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);

ou uma mensagem

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);

em uma observação lateral, essa abordagem pode ser usada, se você desejar executar um pedaço de código no thread da interface do usuário a partir de outro thread.

se você precisar receber uma chamada mesmo que sua atividade não esteja em execução, use um AlarmManager

Samuel
fonte
1
Oh sim, pesquisei exatamente esta resposta. Leve o meu voto positivo para o link útil.
22711 ulidtko
1
atualizou o link, fale sobre o Google tendo problemas para manter os links.
Samuel
1
Este artigo de 2007 - não estou dizendo que está errado, mas sempre desconfio de um artigo para celular se tiver mais de três anos. As coisas mudam muito rapidamente.
StackOverflowed
1
seria mais parecido com o StackOverflow se você pudesse citar os principais pontos do seu link aqui na sua resposta.
N611x007
1
@ Naxa, meus dois centavos para tornar essa resposta mais como StackOverflow.
Samuel
131

Como eu já vi, java.util.Timer é o mais usado para implementar um timer.

Para uma tarefa repetida:

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

Para uma única execução de uma tarefa:

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


tarefa sendo o método a ser executado
após o tempo para a execução inicial
( intervalo para repetir a execução)

Thizzer
fonte
9
Vou apenas acrescentar que o tempo é em milissegundos
Uri
2
Android dev docs for scheduleAtFixedRate
n611x007
1
taskpode ser uma instância da sua classe que herda de java.util.TimerTask e substitui void run().
N611x007
2
Tantas votações. Você poderia fazer isso. Mas @Samuel descreve a melhor maneira. Veja o link "O que é explicado aqui" para saber o porquê. Além disso, não é possível atualizar a interface do usuário a partir de um thread do Timer! E ver essas outras respostas baseadas em Handler em outros tópicos: (simples) stackoverflow.com/a/6702767/199364 , ou (mostra várias alternativas) stackoverflow.com/a/4598737/199364
ToolmakerSteve
@quemeful porque nem sempre se trata de conveniência, é de qualidade e eficiência do código. Essa maneira de fazer isso usa mais recursos do que o manipulador
inDepth
33

Espero que este seja útil e possa levar menos esforços para implementar a classe Android CountDownTimer

por exemplo

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

      public void onFinish() {
          mTextField.setText("done!");
      }  
}.start();
Gaurav Adurkar
fonte
1
Isso é mais fácil e bate na cabeça para uma contagem regressiva simples, como a hora de início da reprodução de um vídeo
Vijay Kumar Kanta
17

Provavelmente 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();

ou

Método 2 ::

Programe o temporizador

Adicione uma nova variável de int chamada time. Defina como 0. Adicione o seguinte código à função onCreate em 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);

Vá para o método run e adicione o seguinte 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
fonte
11

É situacional.

A documentação do Android sugere que você use o AlarmManager para registrar um Intent que será acionado no horário especificado, se o aplicativo não estiver em execução.

Caso contrário, você deve usar o Handler.

Nota: O Gerenciador de alarmes destina-se aos casos em que você deseja que o código do seu aplicativo seja executado em um horário específico, mesmo que seu aplicativo não esteja sendo executado no momento. Para operações normais de cronometragem (ticks, timeouts, etc), é mais fácil e muito mais eficiente usar o Handler.

Timothy Lee Russell
fonte
11

Aqui vamos nós .. Vamos precisar de duas aulas. Estou postando um código que altera o perfil de áudio móvel após cada 5 segundos (5000 mili segundos) ...

Nossa 1ª Classe

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);
    }

}

Nossa 2ª classe

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
fonte
5

Sou iniciante no Android, mas aqui está a classe de timer que criei com base nas respostas acima. Funciona para o meu aplicativo, mas quaisquer sugestões são bem-vindas.

Exemplo 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);
        }
    }; 
}
user868020
fonte
3

Estou usando um manipulador e executável para criar um timer. Eu envolvo isso em uma classe abstrata. Basta derivá-lo / implementá-lo e você estará pronto:

 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);
    }
}

Observe que ele handler.postDelayedé chamado antes do código a ser executado - isso tornará o temporizador mais fechado com o tempo "esperado". No entanto, nos casos em que o cronômetro é executado com frequência e a tarefa ( onTimer()) é longa - pode haver sobreposições. Se você deseja começar a contar intervalMSapós a conclusão da tarefa, mova a onTimer()chamada para uma linha acima.

elcuco
fonte
2

Acredito que a maneira de fazer isso no Android é que você precisa de um serviço em segundo plano para rodar. Nesse aplicativo em segundo plano, crie o cronômetro. Quando o cronômetro "marcar" (defina o intervalo de quanto tempo você deseja esperar), inicie sua atividade que deseja iniciar.

http://developer.android.com/guide/topics/fundamentals.html (<- este artigo explica a relação entre atividades, serviços, intenções e outros fundamentos fundamentais do desenvolvimento do Android)

Crowe T. Robot
fonte
1

Eu costumava usar ( Timer, TimerTask) e também Handleriniciar tarefas (demoradas) periodicamente. Agora mudei o todo para o RxJava. O RxJava fornece Observable.timerque é mais simples, menos propenso a erros e sem complicações.

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
fonte
1

Para operação de temporização, você deve usar Handler .

Se você precisar executar um serviço em segundo plano, o AlarmManager é o caminho a seguir.

robsf
fonte
0

Neste exemplo, inicie a unidade do timer destruída no 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;
            }
        }

    }

Cancelar a timertask em onDestroy ()

timerTask.cancel()
Kshitiz Mishra
fonte