Как повторно выполнять асинхронную задачу через фиксированные промежутки времени

Как заставить асинхронную задачу выполняться повторно через некоторый интервал времени, как и таймер... На самом деле я разрабатываю приложение, которое будет автоматически загружать все последние непрочитанные приветствия с сервера, и для этой цели я должен проверять наличие обновлений с сервера после некоторого фиксированного временные интервалы... Я знаю, что это можно легко сделать с помощью таймера, но я хочу использовать асинхронную задачу, которая, как мне кажется, более эффективна для приложений Android.


person Waseem    schedule 30.06.2011    source источник


Ответы (5)


Вы можете просто обработчик:

private int m_interval = 5000; // 5 seconds by default, can be changed later
private Handle m_handler;

@Override
protected void onCreate(Bundle bundle)
{
  ...
  m_handler = new Handler();
}

Runnable m_statusChecker = new Runnable()
{
     @Override 
     public void run() {
          updateStatus(); //this function can change value of m_interval.
          m_handler.postDelayed(m_statusChecker, m_interval);
     }
}

void startRepeatingTask()
{
    m_statusChecker.run(); 
}

void stopRepeatingTask()
{
    m_handler.removeCallback(m_statusChecker);
}

Но я бы рекомендовал вам проверить эту структуру: http://code.google.com/intl/de-DE/android/c2dm/ Другой подход: сервер уведомит телефон, когда что-то будет готово (таким образом, сэкономив пропускную способность и производительность :))

person kikoso    schedule 30.06.2011
comment
Большое спасибо. На самом деле я просто разрабатываю клиентскую часть приложения. Серверная часть уже работает для того же приложения, разработанного для iphone, и мне приходится использовать тот же сервер для Android. - person Waseem; 30.06.2011
comment
Я новичок в многопоточности в Android. Где вы передаете runnable обработчику? - person Dheeraj Bhaskar; 19.01.2013
comment
чтобы ответить @DheeB, ответчик не упоминает об этом здесь, хотя это должно быть во время создания экземпляра, как это m_handler = new Handler(m_statusChecker); Другая причина, по которой это решение может не сработать, заключается в том, что вопрос ясно указывает на то, что сетевые операции будут автоматически загружать все последнее непрочитанное приветствие с сервера. Поток пользовательского интерфейса, который все еще блокируется. Вам нужно запустить его в отдельном потоке вручную. - person tony9099; 25.09.2013

не было бы более эффективно создать службу и запланировать ее через Alarm Manager?

person Richie    schedule 12.07.2012
comment
Создать сервис — это боль, так много вещей, которые нужно позаботиться о сервисе. Я просто использую таймер. - person Siddharth; 11.02.2013
comment
Службы легко запускать и останавливать. Кроме того, они не привязаны к потоку пользовательского интерфейса. Так что да, я бы использовал сервис. - person IgorGanapolsky; 27.07.2013
comment
@IgorGanapolsky да, они есть. Но с ними тоже хлопотно, зачем создавать асинтаск, таймер и эти модули для более мелких операций, если в них нет смысла и все будет делаться через сервис? - person tony9099; 25.09.2013
comment
@tony9099 AsyncTask предназначен для обновления потока пользовательского интерфейса после завершения. Сервис - нет. Что касается Таймера - его ни туда, ни сюда - он не актуален для сравнения между AsyncTask и Service... - person IgorGanapolsky; 25.09.2013
comment
@IgorGanapolsky точно, однако, если вы внимательно перечитаете вопрос, пользователь захочет проверить некоторые вещи на сервере, получить и обновить пользовательский интерфейс; сценарий, идеально подходящий для асинхронной задачи. - person tony9099; 25.09.2013
comment
Я согласен с Игорем. Из-за проблемы, связанной с уничтожением Activity при повороте устройства (и в других случаях), AsyncTasks гарантированно аварийно завершает работу, если к ним не относятся очень внимательно (чего в этих примерах нет). Реальное решение состоит в том, чтобы стиснуть зубы (да, я знаю, это больно) и оказывать услуги. - person SMBiggs; 08.01.2015

Принятый ответ проблематичен. Использование TimerTask() для активации асинхронной задачи через обработчик — плохая идея. при изменении ориентации вы должны не забыть также отменить вызовы таймера и обработчика. в противном случае он будет вызывать асинхронную задачу снова и снова при каждом вращении. Это приведет к тому, что приложение взорвет сервер (если это остаточный http-запрос на получение) вместо времени X - в конечном итоге вызовы будут вызывать много вызовов каждую секунду. (потому что будет много таймеров по количеству поворотов экрана). Это может привести к сбою приложения, если активность и задача, выполняемая в фоновом потоке, тяжелы. если вы используете таймер, сделайте его мембером класса и отмените его onStop():

            TimerTask mDoAsynchronousTask;


            @Override
            public void onStop(){
               super.onStop();                 
               mDoAsynchronousTask.cancel();
               mHandler.removeCallbacks(null);
               ... 
            }


          public void callAsynchronousTask(final boolean stopTimer) {
             Timer timer = new Timer();
             mDoAsynchronousTask = new TimerTask() {
                 @Override
                 public void run() {
                     mHandler.post(new Runnable() {
                 ...

Вместо этого старайтесь избегать асинхронной задачи, и если вам необходимо использовать службу планировщика для запуска асинхронной задачи. или класс приложения, как в этой хорошей идее: https://fattybeagle.com/2011/02/15/android-asynctasks-during-a-screen-rotation-part-ii/

Или используйте простой обработчик (без таймера, просто используйте postDelayed), а также хорошей практикой является вызов отмены асинхронной задачи onStop(). этот код отлично работает с использованием postDelayed:

           public class MainActivity extends AppCompatActivity {

                  MyAsync myAsync = new MyAsync();

                  private final Handler mSendSSLMessageHandler = new Handler();
                  private final Runnable mSendSSLRunnable = new Runnable(){

                  ..


                 @Override
                 protected void onCreate(Bundle savedInstanceState) {
                    super.onCreate(savedInstanceState);
                    setContentView(R.layout.activity_main);
                    ConnectivityManager connMgr = (ConnectivityManager)   
                    getSystemService(Context.CONNECTIVITY_SERVICE);
                    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
                    if (networkInfo != null && networkInfo.isConnected()) {
                            mSendSSLMessageHandler.post(mSendSSLRunnable);
                    }else
                    ..

                  @Override
                  public void onStop(){
                   super.onStop();
                      if ( progressDialog!=null && progressDialog.isShowing() ){
                           progressDialog.dismiss();
                      }
                    mSendSSLMessageHandler.removeCallbacks(mSendSSLRunnable);
                    myAsync.cancel(false);
                   }


              private final Runnable mSendSSLRunnable = new Runnable(){
              @Override
                public void run(){
                   try {
                    myAsync = new MyAsync();
                    myAsync.execute();
                   } catch (Exception e) {
                      // TODO Auto-generated catch block
                   }
                   mSendSSLMessageHandler.postDelayed(mSendSSLRunnable, 5000);
               }
          };


          class MyAsync extends AsyncTask<Void, Void, String> {
                boolean running = true;

                @Override
                protected void onPreExecute() {
                super.onPreExecute();
                  progressDialog = ProgressDialog.show               
                  (MainActivity.this, "downloading", "please wait");
                }

              @Override
              protected String doInBackground(Void... voids) {
                 if (!running) {
                       return null;
                  }
                 String result = null;
                 try{
                 URL url = new URL("http://192...");
                 HttpURLConnection urlConnection = (HttpURLConnection)            
                 url.openConnection();
                 InputStream in = new BufferedInputStream (urlConnection.getInputStream());
                 result = inputStreamToString(in);
                }catch(Exception e){
                   e.printStackTrace();
                }

               return result;
           }


    @Override
    protected void onCancelled() {
        boolean running = false;
    }
    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        progressDialog.dismiss();
        try {

              ..


        } catch (JSONException e) {
            textView.append("json is invalid");
            e.printStackTrace();
        }

    }


}
person Udi Reshef    schedule 03.10.2018

person    schedule
comment
Асинхронная задача в любом случае выполняется в собственном потоке. Зачем запускать его на обработчике? - person Siddharth; 11.02.2013
comment
Да, асинхронная задача выполняется в отдельном потоке, но ее нельзя запустить из других потоков, кроме потока пользовательского интерфейса. Обработчик, я думаю, существует для того, чтобы разрешить это. - person r1k0; 03.07.2013
comment
Хорошим решением будет использование ScheduledThreadPoolExecutor - stackoverflow.com/a/14377875/1433187. - person Khobaib; 22.03.2014
comment
Следует ли отменить TimerTask в onPause, чтобы Task не продолжал работать после выхода из активности? - person theblang; 18.06.2014
comment
Отлично.. ‹3 Я использую это, чтобы обновить вид беседы в моем приложении.. Tnx! - person mboy; 11.07.2014
comment
Этот метод оставляет висячие ссылки, если действие, которое запускает эти AsyncTasks, уничтожается (из-за изменения ориентации или прерывания ОС, например, телефонного звонка). Так что, если вы довольны тем, что ваше программирование дает сбой в это время, то используйте этот метод во что бы то ни стало. - person SMBiggs; 08.01.2015
comment
@ScottBiggs Какая техника будет лучше/не сбой? - person colti; 16.04.2015
comment
@colti: не нашел хорошего решения. Я отказался от ASyncTasks, за исключением очень простых вещей. Для более сложных действий я использую Службы (да, я знаю, накладные расходы — это головная боль в $$, но, по крайней мере, они не так сильно падают. Просто будьте осторожны, очищайте и не оставляйте висящие службы) . - person SMBiggs; 17.04.2015
comment
Этот код замораживает пользовательский интерфейс. Я использую Сервис. Существует 4 разных вызова API. - person Hardik Joshi; 20.03.2017

person    schedule
comment
Рекомендуется отдавать предпочтение ScheduledThreadPoolExecutor вместо Timer для всего нового кода в документации Android разработчика. android.com/reference/java/util/Timer.html - person Martin O'Shea; 06.06.2016