Как запускать метод каждые X секунд


114

Я разрабатываю приложение для Android 2.3.3, и мне нужно запускать метод каждые X секунд .

В iOS у меня есть NSTimer , но в Android я не знаю, что использовать.

Кто-то порекомендовал мне Хендлера ; другой порекомендовал мне AlarmManager, но я не знаю, какой метод лучше подходит для NSTimer .

Это код, который я хочу реализовать в 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
];

Мне нужно что-то, что работает как NSTimer .

Что вы мне порекомендуете?


1
Определите «лучший». Каким образом вы хотите, чтобы он был лучшим?
— Саймон Форсберг

Я не знаю, какой метод лучше подходит для NSTimer.
— VansFannel

@VansFannel Как долго вы хотите перерыв?
— FoamyGuy

Я обновил вопрос, указав подробности того, что я пытаюсь сделать.
— VansFannel

Этот вопрос: stackoverflow.com/questions/6242268/… похож на этот и имеет отличный ответ.
— VansFannel

Ответы:


169

Это действительно зависит от того, как долго вам нужно запускать функцию.

Если это => 10 минут → я бы выбрал 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();
}

А затем вы получаете эти трансляции через широковещательный приемник. Обратите внимание, что это нужно будет зарегистрировать в эфире в манифесте вашего приложения или с помощью context.registerReceiver(receiver,filter);метода. Для получения дополнительной информации о широковещательных приемниках обратитесь к официальной документации. Приемник трансляции .

public class MyReceiver extends BroadcastReceiver{

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

Если это = <10 минут → я бы пошел с обработчиком.

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

handler.postDelayed(new Runnable(){
    public void run(){
        //do something
        handler.postDelayed(this, delay);
    }
}, delay);

3
Почему разные предложения в зависимости от задержки?
— Саймон Форсберг

7
Эффективность. В документации AlarmManager указано, что его не следует использовать для каких-либо повторяющихся задач с небольшим интервалом.
— Jug6ernaut

9
@ SimonAndréForsberg в документации AlarmManager заявляет, что Handler - это предпочтительный и более эффективный метод для коротких тиков: «Примечание. Alarm Manager предназначен для случаев, когда вы хотите, чтобы код вашего приложения запускался в определенное время, даже если ваш приложение в настоящее время не запущено. Для обычных операций с таймингом (такты, тайм-ауты и т. д.) проще и эффективнее использовать Handler. "
— FoamyGuy

Но мне нужно запустить метод в том же действии, которое запустило AlarmManager. Как я могу это сделать?
— VansFannel

2
@ahmadalibaloch из runnable, который вы можете сделать h.removeCallbacks(this);, иначе вам нужно поддерживать ссылку на runnable, чтобы иметь возможность удалить его. Если второй вариант желателен, описанный здесь метод может быть не лучшим вариантом.
— Jug6ernaut

101

Используйте таймер на каждую секунду ...

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        //your method
    }
}, 0, 1000);//put here time 1000 milliseconds=1 second

Я обновил вопрос, указав подробности того, что я пытаюсь сделать.
— VansFannel

4
Не используйте Timer ( mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler ), используйте Handler или ScheduledThreadPoolExecutor.
— AppiDevo

69

Вы можете попробовать этот код, чтобы вызывать обработчик каждые 15 секунд через onResume () и останавливать его, когда активность не отображается, через 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();
}

5
Это то, что я искал. Отлично.
— viper

3
это идеальный ответ!
— Риддхи

Пятно! Использование для проверки MainActivitys текущей выбранной вкладки в TabLayout соответствует этому фрагменту, и если не остановить работу - так как onPause () не работает, когда любой TabLayout выбранные вкладки по обе стороны от этой выбранной вкладки
— BENN1TH

идеальный. Это было то, что я искал :) 1 вопрос, могу ли я вызвать этот метод из другого действия. Или, если я завершу это действие, этот объект будет уничтожен? Что, если я создам статический обработчик и выполню его. Это возможно?
— hyperCoder

17

Если вы знакомы с RxJava, вы можете использовать Observable.interval (), что довольно удобно.

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

Обратной стороной этого является то, что вам придется по-другому спроектировать опрос данных. Тем не менее, у способа реактивного программирования есть много преимуществ:

  1. Вместо того, чтобы контролировать свои данные с помощью обратного вызова, вы создаете поток данных, на который подписываетесь. Это разделяет логику «опроса данных» и логику «заполнения пользовательского интерфейса данными», чтобы вы не смешивали код «источника данных» и код пользовательского интерфейса.
  2. С RxAndroid вы можете обрабатывать потоки всего в 2 строчки кода.

    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

Пожалуйста, проверьте RxJava. У него высокая кривая обучения, но он сделает обработку асинхронных вызовов в Android намного проще и чище.


4

С помощью Kotlin мы теперь можем создать для этого универсальную функцию!

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

А чтобы использовать, просто сделайте:

val delay = 1000L
RepeatHelper.repeatDelayed(delay) {
    myRepeatedFunction()
}

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

4
Не размещайте код, только ответ. Пожалуйста, отредактируйте свой ответ и добавьте пояснение.
— Shashanth

2

Здесь я повторно использовал поток в onCreate () Activity, таймер не позволяет все в некоторых случаях Thread - это решение

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

В случае необходимости его можно остановить

@Override
protected void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    //t.interrupted();
}

опишите, пожалуйста, ситуацию, когда мой ответ не сработает
— Умар Ата

Привет Умар. Мне нужен был круг все время, пока живо приложение, Хэндлер делал повторение, пока активна активность, но мне нужен круг, пока я мог посещать и другие занятия. Таким образом, поток - это решение, и у него тоже есть свои проблемы.
— Сэм

1

Здесь может быть полезен ответ на вашу проблему с использованием Rx Java и Rx Android .

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.