Планирование повторяющихся задач в Android



Я разрабатываю приложение, которое имеет повторяющуюся задачу отправки присутствия на выделенный сервер, пока приложение находится на переднем плане.



в моих поисках через интернет я увидел несколько различных подходов и хотел бы знать, что это лучший способ сделать это.



каков наилучший способ запланировать вызов сервера?



параметры которые я видел, были:




  1. таймер .


  2. ScheduledThreadPoolExecutor.


  3. сервис.


  4. BroadcastReciever с AlarmManager.



каково Ваше мнение?



EDIT:
причина, по которой мне это нужно, - это приложение на основе чата, которое отправляет все действия пользователя на удаленный сервер.
т. е. пользователь вводит сообщение, пользователь прочитав сообщение, пользователь онлайн, пользователь оффлайн и т. д.



это означает, что каждый раз, когда мне нужно отправить сервер, что я делаю, так как я открываю чат с другими людьми, они должны знать, что я делаю.



похоже на механизм обратной связи сообщений whatsapp:
message looks delivered



EDIT #2:

Повторяющиеся задачи теперь должны быть запланированы почти всегда через JobScheduler API (или FirebaseJobDispatcher для более низких API) для того чтобы предотвратите проблемы с разряжением батареи, как можно прочитать в раздел жизненно важных органов из Android обучения

623   6  

6 ответов:

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

Alarm Manager

диспетчер сигналов тревоги держит блокировку пробуждения процессора до тех пор, пока приемник сигнала тревоги onReceive() метод выполнения. Это гарантирует, что телефон не будет спать, пока вы не закончите обработку эфира. Один раз onReceive() возвращается, диспетчер будильника освобождает эту блокировку пробуждения. Это означает, что телефон в некоторых случаях будет спать как как только ваш onReceive() метод завершается. Если ваш приемник тревоги называется Context.startService(), возможно, что телефон будет спать до начала запрашиваемую услугу. Чтобы предотвратить это, ваш BroadcastReceiver и Service необходимо будет реализовать отдельную политику блокировки пробуждения, чтобы гарантировать, что телефон продолжает работать, пока услуга не станет доступной.

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

таймер

timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {

        synchronized public void run() {

            \ here your todo;
            }

        }}, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1));

Timer имеет некоторые недостатки, которые решаются с помощью ScheduledThreadPoolExecutor. Так что это не лучший выбор

ScheduledThreadPoolExecutor.

можно использовать java.util.Timer или ScheduledThreadPoolExecutor (предпочтительно), чтобы запланировать действие, которое будет происходить через регулярные промежутки времени на фоне нитка.

вот пример использования последнего:

ScheduledExecutorService scheduler =
    Executors.newSingleThreadScheduledExecutor();

scheduler.scheduleAtFixedRate
      (new Runnable() {
         public void run() {
            // call service
         }
      }, 0, 10, TimeUnit.MINUTES);

так что я предпочел ScheduledExecutorService

, но и думать о том, что если обновления будут происходить во время работы приложения, вы можете использовать Timer, как предлагается в других ответах, или более новые ScheduledThreadPoolExecutor. Если ваше приложение будет обновляться даже тогда, когда оно не работает, вы должны пойти с AlarmManager.

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

обратите внимание, что если вы планируете обновление, когда ваше приложение выключено, один раз в десять минут довольно часто, и, таким образом, возможно, слишком много энергии.

таймер

как уже упоминалось на документации вам лучше использовать ScheduledThreadPoolExecutor.

ScheduledThreadPoolExecutor

используйте этот класс, когда ваш вариант использования требует нескольких рабочих потоков и интервал сна мал. Насколько маленький ? Ну, я бы сказал, около 15 минут. Элемент AlarmManager запускает интервалы расписания в это время, и это, кажется, предполагает, что для меньших интервалов сна этот класс может быть использован. У меня нет данных, чтобы вернемся к последнему утверждению. Это предчувствие.

сервис

ваш сервис может быть закрыт в любое время по ВМ. Не используйте службы для повторяющихся задач. Повторяющаяся задача может start служба,что совсем другое дело.

BroadcastReciever с AlarmManager

для более длинних интервалов сна (>15 минут), это путь пойти. AlarmManager уже есть константы ( AlarmManager.INTERVAL_DAY) предполагая, что он может запускать задачи через несколько дней после него изначально было запланировано. Он также может разбудить процессор для запуска вашего кода.

вы должны использовать одно из этих решений на основе ваших потребностей времени и рабочего потока.

Я понимаю, что это старый вопрос и был дан ответ, но это может помочь кому-то. В вашем activity

private ScheduledExecutorService scheduleTaskExecutor;

на onCreate

  scheduleTaskExecutor = Executors.newScheduledThreadPool(5);

    //Schedule a task to run every 5 seconds (or however long you want)
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            // Do stuff here!

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Do stuff to update UI here!
                    Toast.makeText(MainActivity.this, "Its been 5 seconds", Toast.LENGTH_SHORT).show();
                }
            });

        }
    }, 0, 5, TimeUnit.SECONDS); // or .MINUTES, .HOURS etc.

со ссылкой на планирование повторяющихся сигналов тревоги-понять компромиссы документы:

распространенным сценарием запуска операции вне времени существования вашего приложения является синхронизация данных с сервером. Это тот случай, когда у вас может возникнуть соблазн использовать повторяющийся сигнал тревоги. Но если у вас есть сервер, на котором размещаются данные вашего приложения, использование Google Cloud Messaging (GCM) в сочетании с адаптером синхронизации является лучшим решением, чем AlarmManager. Адаптер синхронизации дает вам все те же параметры планирования, что и AlarmManager, но он предлагает вам значительно большую гибкость.

Итак, исходя из этого, лучший способ запланировать вызов сервера-использовать Google Cloud Messaging (GCM) в сочетании с адаптер синхронизации.

Я создал на время задачу, в которой задача, которую пользователь хочет повторить, добавить в пользовательский метод TimeTask run (). это успешно повторяется.

 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Timer;
 import java.util.TimerTask;

 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.TextView;
 import android.app.Activity;
 import android.content.Intent;

 public class MainActivity extends Activity {

     CheckBox optSingleShot;
     Button btnStart, btnCancel;
     TextView textCounter;

     Timer timer;
     MyTimerTask myTimerTask;

     int tobeShown = 0  ;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    optSingleShot = (CheckBox)findViewById(R.id.singleshot);
    btnStart = (Button)findViewById(R.id.start);
    btnCancel = (Button)findViewById(R.id.cancel);
    textCounter = (TextView)findViewById(R.id.counter);
    tobeShown = 1;

    if(timer != null){
        timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
        //singleshot delay 1000 ms
        timer.schedule(myTimerTask, 1000);
    }else{
        //delay 1000ms, repeat in 5000ms
        timer.schedule(myTimerTask, 1000, 1000);
    }

    btnStart.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View arg0) {


            Intent i = new Intent(MainActivity.this, ActivityB.class);
            startActivity(i);

            /*if(timer != null){
                timer.cancel();
            }

            //re-schedule timer here
            //otherwise, IllegalStateException of
            //"TimerTask is scheduled already" 
            //will be thrown
            timer = new Timer();
            myTimerTask = new MyTimerTask();

            if(optSingleShot.isChecked()){
                //singleshot delay 1000 ms
                timer.schedule(myTimerTask, 1000);
            }else{
                //delay 1000ms, repeat in 5000ms
                timer.schedule(myTimerTask, 1000, 1000);
            }*/
        }});

    btnCancel.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
            if (timer!=null){
                timer.cancel();
                timer = null;
            }
        }
    });

}

@Override
protected void onResume() {
    super.onResume();

    if(timer != null){
        timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
        //singleshot delay 1000 ms
        timer.schedule(myTimerTask, 1000);
    }else{
        //delay 1000ms, repeat in 5000ms
        timer.schedule(myTimerTask, 1000, 1000);
    }
}


@Override
protected void onPause() {
    super.onPause();

    if (timer!=null){
        timer.cancel();
        timer = null;
    }

}

@Override
protected void onStop() {
    super.onStop();

    if (timer!=null){
        timer.cancel();
        timer = null;
    }

}

class MyTimerTask extends TimerTask {

    @Override
    public void run() {

        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = 
                new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
        final String strDate = simpleDateFormat.format(calendar.getTime());

        runOnUiThread(new Runnable(){

            @Override
            public void run() {
                textCounter.setText(strDate);
            }});
    }
}

}

может быть, это не ответ на ваш вопрос, но советы для структуры вашего приложения. Что касается меня, то гораздо проще использовать узел JS с SOCKET.IO для таких приложений, как чат. И поскольку это в режиме реального времени, вам не нужно спрашивать сервер каждый раз. Там вы можете прочитать больше о SOCET IO -- http://socket.io/

Comments

    Ничего не найдено.