Jak uruchomić metodę co X sekund

114

Tworzę aplikację na Androida 2.3.3 i muszę uruchamiać metodę co X sekund .

W iOS mam NSTimer , ale na Androidzie nie wiem, czego użyć.

Ktoś polecił mi Handler ; inny polecam AlarmManager ale nie wiem, która metoda lepiej pasuje do NSTimer .

Oto kod, który chcę zaimplementować w systemie 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
];

Potrzebuję czegoś, co działa jak NSTimer .

Co mi polecasz?

VansFannel
źródło
1
Zdefiniuj „najlepszy”. W jaki sposób chcesz, aby był najlepszy?
Simon Forsberg,
Nie wiem, która metoda lepiej pasuje do NSTimer.
VansFannel,
@VansFannel Jak długi przedział chcesz?
FoamyGuy,
Zaktualizowałem pytanie o szczegóły dotyczące tego, co próbuję zrobić.
VansFannel,
To pytanie: stackoverflow.com/questions/6242268/… , jest podobne do tego i ma świetną odpowiedź.
VansFannel,

Odpowiedzi:

169

To naprawdę zależy od tego, jak długo trzeba będzie uruchomić tę funkcję.

Jeśli jest => 10 minut → wybrałbym Menedżera alarmów.

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

A następnie odbierasz te transmisje za pośrednictwem odbiornika. Należy pamiętać, że będzie to musiało zostać zarejestrowane w manifeście aplikacji lub za pomocą context.registerReceiver(receiver,filter);metody. Więcej informacji na temat odbiorników transmisji można znaleźć w oficjalnych dokumentach. Odbiornik transmisji .

public class MyReceiver extends BroadcastReceiver{

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

Jeśli to = <10 minut → pójdę z Handlerem.

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

handler.postDelayed(new Runnable(){
    public void run(){
        //do something
        handler.postDelayed(this, delay);
    }
}, delay);
Jug6ernaut
źródło
3
Po co różne sugestie w zależności od opóźnienia?
Simon Forsberg,
7
Wydajność, w dokumentacji AlarmManager stwierdza, że ​​nie powinno się go używać do żadnych powtarzalnych zadań o małych odstępach czasu.
Jug6ernaut,
9
@ SimonAndréForsberg w dokumentacji AlarmManager stwierdza, że ​​Handler jest preferowaną i bardziej efektywną metodą do użycia dla krótkich tików: "Uwaga: Menedżer alarmów jest przeznaczony do przypadków, w których chcesz, aby kod aplikacji był uruchamiany w określonym czasie, nawet jeśli aplikacja nie jest obecnie uruchomiona. W przypadku normalnych operacji związanych z synchronizacją (takty, przekroczenia limitu czasu itp.) łatwiejsze i znacznie wydajniejsze jest użycie programu Handler. "
FoamyGuy,
Ale muszę uruchomić metodę w tym samym działaniu, które uruchomiło AlarmManager. Jak mogę to zrobić?
VansFannel,
2
@ahmadalibaloch z poziomu runnable, które możesz zrobić h.removeCallbacks(this);, w przeciwnym razie musisz zachować odniesienie do runnable, aby móc go usunąć. Jeśli druga strona jest pożądana, zamieszczona tutaj metoda może nie być najlepszą trasą.
Jug6ernaut
101

Używaj timera co sekundę ...

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        //your method
    }
}, 0, 1000);//put here time 1000 milliseconds=1 second
Samir Mangroliya
źródło
Zaktualizowałem pytanie o szczegóły dotyczące tego, co próbuję zrobić.
VansFannel,
4
Nie używaj Timera ( mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler ), używaj Handler lub ScheduledThreadPoolExecutor.
AppiDevo
69

Możesz spróbować tego kodu, aby wywoływać program obsługi co 15 sekund za pomocą onResume () i zatrzymywać go, gdy aktywność nie jest widoczna, za pomocą 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
źródło
5
To jest to, czego szukałem. Idealny.
viper
3
to idealna odpowiedź!
Riddhi
Na miejscu! Używanie do sprawdzania aktualnie wybranej karty MainActivitys w TabLayout pasuje do tego fragmentu i jeśli nie, zatrzymaj pracę - tak jak onPause () kończy się niepowodzeniem, gdy dowolne TabLayout wybrane karty po obu stronach tej wybranej karty
BENN1TH
idealny. Tego szukałem :) 1 pytanie, czy mogę tę metodę nazwać z innego ćwiczenia. Czy jeśli wykonam tę czynność, ten obiekt zostanie zniszczony? Co się stanie, jeśli utworzę statyczną procedurę obsługi i będzie można ją uruchomić. Czy to jest możliwe?
hyperCoder,
17

Jeśli znasz RxJava, możesz użyć Observable.interval (), co jest całkiem fajne.

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

Wadą tego jest to, że musisz zaprojektować architekturę sondowania danych w inny sposób. Jednak sposób programowania reaktywnego ma wiele zalet:

  1. Zamiast kontrolować swoje dane poprzez wywołanie zwrotne, tworzysz strumień danych, który subskrybujesz. Oddziela to obawy związane z logiką „odpytywania danych” i logiką „wypełniania interfejsu użytkownika danymi”, aby nie mieszać kodu „źródła danych” i kodu interfejsu użytkownika.
  2. Dzięki RxAndroid możesz obsługiwać wątki w zaledwie 2 wierszach kodu.

    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

Proszę sprawdź RxJava. Ma dużą krzywą uczenia się, ale sprawi, że obsługa wywołań asynchronicznych w systemie Android będzie o wiele łatwiejsza i czystsza.

wdina
źródło
4

Dzięki Kotlinowi możemy teraz stworzyć dla tego funkcję ogólną!

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

Aby użyć, po prostu wykonaj:

val delay = 1000L
RepeatHelper.repeatDelayed(delay) {
    myRepeatedFunction()
}
Łukasz
źródło
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
źródło
4
Nie wysyłaj tylko kodu pocztowego. Proszę edytować swoje odpowiedzi i dodać kilka wyjaśnień.
Shashanth
2

Tutaj użyłem wątku w onCreate () wielokrotnie, licznik czasu nie pozwala na wszystko w niektórych przypadkach Wątek jest rozwiązaniem

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

W razie potrzeby można go zatrzymać

@Override
protected void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    //t.interrupted();
}
Sam
źródło
proszę opisać sytuację, w której moja odpowiedź nie zadziała
Umar Ata
Cześć Umar. Potrzebowałem koła przez cały czas, gdy ta aplikacja działa, Handler ożywił powtórzenia, gdy aktywność jest żywa, ale potrzebuję koła, gdy mogłem też odwiedzać inne zajęcia. Więc nić jest rozwiązaniem w ten sposób, że ma również swoją walkę.
Sam
1

Tutaj może pomocna odpowiedź na Twój problem z użyciem Rx Java i Rx Android .

Sepehr
źródło