如何在固定时间间隔后重复执行异步任务

Posted

技术标签:

【中文标题】如何在固定时间间隔后重复执行异步任务【英文标题】:How to execute Async task repeatedly after fixed time intervals 【发布时间】:2011-09-25 19:02:33 【问题描述】:

如何让异步任务像定时器一样在一段时间间隔后重复执行...实际上我正在开发一个应用程序,它将自动从服务器下载所有最新的未读问候语,为此我必须检查来自服务器的更新经过一些固定的时间间隔......我知道这可以通过计时器轻松完成,但我想使用我认为对 android 应用程序更有效的异步任务。

【问题讨论】:

【参考方案1】:
public void callAsynchronousTask() 
    final Handler handler = new Handler();
    Timer timer = new Timer();
    TimerTask doAsynchronousTask = new TimerTask()        
        @Override
        public void run() 
            handler.post(new Runnable() 
                public void run()        
                    try 
                        PerformBackgroundTask performBackgroundTask = new PerformBackgroundTask();
                        // PerformBackgroundTask this class is the class that extends AsynchTask 
                        performBackgroundTask.execute();
                     catch (Exception e) 
                        // TODO Auto-generated catch block
                    
                
            );
        
    ;
    timer.schedule(doAsynchronousTask, 0, 50000); //execute in every 50000 ms

【讨论】:

Async Task 无论如何都在它自己的线程中运行。为什么要在处理程序上运行它? 是的,异步任务确实在单独的线程上运行,但不能从 UI 线程以外的其他线程启动。我猜,处理程序是为了允许这样做。 如果启动这些 AsyncTask 的 Activity 被终止(通过方向更改或操作系统中断,如电话呼叫),此技术会留下悬空引用。因此,如果您对自己的程序在这些时候崩溃感到满意,那么请务必使用此方法。 @ScottBiggs 哪种技术会更好/不会崩溃? @colti:还没有找到好的解决方案。除了非常简单的东西外,我已经放弃了 ASyncTasks。对于更复杂的操作,我使用服务(是的,我知道,开销是一个痛苦的$$,但至少它不会崩溃那么多。小心清理,不要留下悬空的服务) .【参考方案2】:
  //Every 10000 ms   
       private void doSomethingRepeatedly() 
      Timer timer = new Timer();
      timer.scheduleAtFixedRate( new TimerTask() 
            public void run() 

                  try

                     new SendToServer().execute(); 

                  
                  catch (Exception e) 
                      // TODO: handle exception
                  

             
            , 0, 10000);
                     

【讨论】:

对于android文档developer.android.com/reference/java/util/Timer.html中的所有新代码,建议优先使用ScheduledThreadPoolExecutor而不是Timer【参考方案3】:

你可以只是一个处理程序:

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/ 是一种不同的方法:服务器会在准备就绪时通知手机(从而节省一些带宽和性能:))

【讨论】:

非常感谢。实际上我只是在开发应用程序的客户端。服务器端已经在为 iphone 开发的相同应用程序工作,我必须为 android 使用相同的服务器 我是 android 线程的新手。你在哪里将 runnable 传递给处理程序? 回答@DheeB,回答者在这里没有提到,虽然它应该在像这样的实例化过程中 m_handler = new Handler(m_statusChecker);该解决方案可能不起作用的另一个原因,因为问题清楚地表明将有网络操作“自动从服务器下载所有最新的未读问候语”。但是,尽管您使用的是处理程序,但此处理程序/可运行文件仍在运行在仍然阻塞的 UI 线程中。您需要手动在单独的线程中启动它。【参考方案4】:

通过警报管理器创建服务并安排它不是更有效吗?

【讨论】:

创建一个服务是一件很痛苦的事,所以要在一个服务上处理很多事情。我宁愿只使用计时器。 服务易于启动和停止。另外,它们不依赖于 UI 线程。所以是的,我会使用服务。 @IgorGanapolsky 是的。但是它们也很麻烦,如果它们没有意义并且一切都将通过服务完成,为什么还要为较小的操作创建异步任务、计时器和这些模块? @tony9099 AsyncTask 用于在完成后更新 UI 线程。服务不是。至于 Timer - 它既不存在也不存在 - 它与 AsyncTask 和 Service 之间的比较无关...... 我同意伊戈尔的观点。由于在设备旋转时(以及其他时间)如何杀死活动的问题,除非非常仔细地处理(在这些示例中没有),否则 AsyncTask 肯定会崩溃。真正的解决方案是咬紧牙关(是的,我知道,这很痛苦)并提供服务。【参考方案5】:

接受的答案有问题。 使用 TimerTask() 通过处理程序激活异步任务是一个坏主意。在方向更改时,您必须记住取消计时器和处理程序调用。如果不是,它将在每次轮换时一次又一次地调用异步任务。 这将导致应用程序炸毁服务器(如果这是休息 http get 请求)而不是 X 时间 - 最终调用将是每秒实例多次调用。 (因为根据屏幕旋转的次数会有很多定时器)。如果在后台线程中运行的活动和任务很重,它可能会破坏应用程序。 如果您使用计时器,则将其设为类 memebr 并在 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();
        

    



【讨论】:

以上是关于如何在固定时间间隔后重复执行异步任务的主要内容,如果未能解决你的问题,请参考以下文章

Python—定时任务

“异步任务然后等待任务”与“任务然后返回任务”[重复]

python的sched模块可​​以在任务执行期间不阻塞地运行异步任务吗?

在异步任务中给出异常的进度对话框[重复]

如何按预定义的秒数终止异步任务请求[重复]

java 每间隔一段时间执行一段代码