Como executar um método a cada X segundos

114

Estou desenvolvendo um aplicativo Android 2.3.3 e preciso executar um método a cada X segundos .

No iOS tenho o NSTimer , mas no Android não sei o que usar.

Alguém me recomendou Handler ; outro me recomendou AlarmManager, mas não sei qual método se encaixa melhor com NSTimer .

Este é o código que desejo implementar no Android:

timer2 = [
    NSTimer scheduledTimerWithTimeInterval:(1.0f/20.0f)
    target:self
    selector:@selector(loopTask)
    userInfo:nil
    repeats:YES
];

timer1 = [
    NSTimer scheduledTimerWithTimeInterval:(1.0f/4.0f)
    target:self
    selector:@selector(isFree)
    userInfo:nil
    repeats:YES
];

Preciso de algo que funcione como NSTimer .

O que você me recomenda?

VansFannel
fonte
1
Defina "o melhor". De que forma você quer que seja o melhor?
Simon Forsberg
Não sei qual método se encaixa melhor com o NSTimer.
VansFannel
@VansFannel Quanto tempo de intervalo você deseja?
FoamyGuy
Atualizei a pergunta com detalhes sobre o que estou tentando fazer.
VansFannel
Esta pergunta: stackoverflow.com/questions/6242268/… , é semelhante a esta e tem uma ótima resposta.
VansFannel

Respostas:

168

Isso realmente depende de quanto tempo você precisa para executar a função.

Se for => 10 minutos → eu iria com Alarm Manager.

// Some time when you want to run
Date when = new Date(System.currentTimeMillis());    

try{
   Intent someIntent = new Intent(someContext,MyReceiver.class); // intent to be launched

   // note this could be getActivity if you want to launch an activity
   PendingIntent pendingIntent = PendingIntent.getBroadcast(
        context, 
        0, // id, optional
        someIntent, // intent to launch
        PendingIntent.FLAG_CANCEL_CURRENT); // PendintIntent flag

   AlarmManager alarms = (AlarmManager) context.getSystemService(
        Context.ALARM_SERVICE);

   alarms.setRepeating(AlarmManager.RTC_WAKEUP,
        when.getTime(),
        AlarmManager.INTERVAL_FIFTEEN_MINUTES,
        pendingIntent); 

}catch(Exception e){
   e.printStackTrace();
}

E então você recebe essas transmissões via receptor de transmissão. Observe que isso precisará ser registrado ether em seu manifesto de aplicativo ou por meio do context.registerReceiver(receiver,filter);método. Para obter mais informações sobre Broadcast Receivers, consulte os documentos oficiais. Receptor de transmissão .

public class MyReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) 
    {
         //do stuffs
    }
}

Se for = <10 minutos → eu iria com um Handler.

Handler handler = new Handler();
int delay = 1000; //milliseconds

handler.postDelayed(new Runnable(){
    public void run(){
        //do something
        handler.postDelayed(this, delay);
    }
}, delay);
Jug6ernaut
fonte
3
Por que sugestões diferentes dependendo do atraso?
Simon Forsberg
7
Eficiência, no documento AlarmManager afirma que não deve ser usado para nenhuma tarefa repetitiva de pequeno intervalo.
Jug6ernaut
9
@ SimonAndréForsberg na documentação do AlarmManager afirma que Handler é o método preferido e mais eficiente para usar tiques curtos: "Nota: O Alarm Manager é destinado a casos em que você deseja que o código do seu aplicativo seja executado em um momento específico, mesmo que o seu o aplicativo não está em execução no momento. Para operações de temporização normais (tiques, tempos limite, etc.), é mais fácil e muito mais eficiente usar o Handler. "
FoamyGuy
Porém, preciso executar um método na mesma Activity que iniciou o AlarmManager. Como eu posso fazer isso?
VansFannel
2
@ahmadalibaloch de dentro do executável você pode fazer h.removeCallbacks(this);, caso contrário, você precisa manter uma referência ao executável para poder removê-lo. Se o segundo for desejado, o método postado aqui pode não ser seu melhor caminho.
Jug6ernaut
101

Use o cronômetro para cada segundo ...

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        //your method
    }
}, 0, 1000);//put here time 1000 milliseconds=1 second
Samir Mangroliya
fonte
Atualizei a pergunta com detalhes sobre o que estou tentando fazer.
VansFannel
4
Não use Timer ( mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler ), use Handler ou ScheduledThreadPoolExecutor.
AppiDevo
69

Você pode tentar este código para chamar o manipulador a cada 15 segundos via onResume () e interrompê-lo quando a atividade não estiver visível, via onPause ().

Handler handler = new Handler();
Runnable runnable;
int delay = 15*1000; //Delay for 15 seconds.  One second = 1000 milliseconds.


@Override
protected void onResume() {
   //start handler as activity become visible

    handler.postDelayed( runnable = new Runnable() {
        public void run() {
            //do something

            handler.postDelayed(runnable, delay);
        }
    }, delay);

    super.onResume();
}

// If onPause() is not included the threads will double up when you 
// reload the activity 

@Override
protected void onPause() {
    handler.removeCallbacks(runnable); //stop handler when activity not visible
    super.onPause();
}
Umar Ata
fonte
5
Isso é o que eu estava procurando. Perfeito.
viper
3
essa é a resposta perfeita!
Riddhi
Spot on! Usar para verificar MainActivitys a guia selecionada atual em TabLayout corresponde a este fragmento e se não parar de funcionar - como onPause () falha quando qualquer guia selecionada de TabLayout em qualquer um dos lados desta guia selecionada
BENN1TH
perfeito. Era isso que eu procurava :) 1 pergunta, posso chamar esse método a partir de outra atividade. Ou se eu evitar essa atividade, esse objeto será destruído? E se eu criar um manipulador estático e executável. Isso é possível?
hyperCoder
17

Se você está familiarizado com o RxJava, pode usar Observable.interval (), que é muito legal.

Observable.interval(60, TimeUnits.SECONDS)
          .flatMap(new Function<Long, ObservableSource<String>>() {
                @Override
                public ObservableSource<String> apply(@NonNull Long aLong) throws Exception {
                    return getDataObservable(); //Where you pull your data
                }
            });

A desvantagem disso é que você precisa arquitetar a pesquisa de seus dados de uma maneira diferente. No entanto, há muitos benefícios no modo de Programação Reativa:

  1. Em vez de controlar seus dados por meio de um retorno de chamada, você cria um fluxo de dados que você assina. Isso separa a preocupação da lógica de "dados de pesquisa" e da lógica de "preencher a IU com seus dados" para que você não misture seu código de "fonte de dados" e seu código de IU.
  2. Com RxAndroid, você pode lidar com threads em apenas 2 linhas de código.

    Observable.interval(60, TimeUnits.SECONDS)
          .flatMap(...) // polling data code
          .subscribeOn(Schedulers.newThread()) // poll data on a background thread
          .observeOn(AndroidSchedulers.mainThread()) // populate UI on main thread
          .subscribe(...); // your UI code

Por favor, verifique RxJava. Ele tem uma alta curva de aprendizado, mas tornará o tratamento de chamadas assíncronas no Android muito mais fácil e limpo.

wdina
fonte
4

Com o Kotlin, agora podemos fazer uma função genérica para isso!

object RepeatHelper {
    fun repeatDelayed(delay: Long, todo: () -> Unit) {
        val handler = Handler()
        handler.postDelayed(object : Runnable {
            override fun run() {
                todo()
                handler.postDelayed(this, delay)
            }
        }, delay)
    }
}

E para usar, basta fazer:

val delay = 1000L
RepeatHelper.repeatDelayed(delay) {
    myRepeatedFunction()
}
Lucas
fonte
3
    new CountDownTimer(120000, 1000) {

        public void onTick(long millisUntilFinished) {
            txtcounter.setText(" " + millisUntilFinished / 1000);

        }

        public void onFinish() {

            txtcounter.setText(" TimeOut  ");
            Main2Activity.ShowPayment = false;
            EventBus.getDefault().post("go-main");

        }

    }.start();
Behzad F94
fonte
4
Não poste código apenas para responder. Por favor edite sua resposta e adicionar um pouco de explicação.
Shashanth de
2

Aqui eu usei um thread em onCreate () uma Activity repetidamente, o timer não permite tudo em alguns casos Thread é a solução

     Thread t = new Thread() {
        @Override
        public void run() {
            while (!isInterrupted()) {
                try {
                    Thread.sleep(10000);  //1000ms = 1 sec
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            SharedPreferences mPrefs = getSharedPreferences("sam", MODE_PRIVATE);
                            Gson gson = new Gson();
                            String json = mPrefs.getString("chat_list", "");
                            GelenMesajlar model = gson.fromJson(json, GelenMesajlar.class);
                            String sam = "";

                            ChatAdapter adapter = new ChatAdapter(Chat.this, model.getData());
                            listview.setAdapter(adapter);
                           // listview.setStackFromBottom(true);
                          //  Util.showMessage(Chat.this,"Merhabalar");
                        }
                    });

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    t.start();

Caso seja necessário, pode ser interrompido por

@Override
protected void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    //t.interrupted();
}
Sam
fonte
descreva a situação em que minha resposta não funcionou
Umar Ata
Hello Umar. Eu precisava de um círculo durante todo o tempo em que o aplicativo estava ativo, Handler fez a repetição viva enquanto a atividade estava viva, mas eu preciso do círculo enquanto pude visitar outras atividades também. Portanto, thread é solução dessa forma, com certeza também tem sua luta.
Sam
1

Esta pode ser uma resposta útil para o seu problema usando Rx Java e Rx Android .

Sepehr
fonte