Как запускать метод каждые 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 .

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

VansFannel
источник
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);
Jug6ernaut
источник
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 намного проще и чище.

Wdina
источник
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();
Бехзад F94
источник
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 .

Sepehr
источник