如何在安卓系统中每 x 分钟运行一次异步任务?

50

如何在特定时间运行异步任务?(我希望每2分钟运行一次)

我尝试使用postDelayed,但它不起作用?

    tvData.postDelayed(new Runnable(){

    @Override
    public void run() {
        readWebpage();

    }}, 100);
在以上代码中,readwebpage是一个调用异步任务的函数。
现在我正在使用以下方法。
   public void onCreate(Bundle savedInstanceState) {

         readwebapage();

   }

   public void readWebpage() {
    DownloadWebPageTask task = new DownloadWebPageTask();
    task.execute("http://www.google.com");

   }

   private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... urls) {
        String response1 = "";
        response1=read(); 
                   //read is my another function which does the real work    
        response1=read(); 
        super.onPostExecute(response1);
        return response1;
    }


      protected void onPostExecute(String result) {


         try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            TextView tvData = (TextView) findViewById(R.id.TextView01);
            tvData.setText(result);

        DownloadWebPageTask task = new DownloadWebPageTask();
        task.execute(new String[] { "http://www.google.com" });

    }

    }

这就是我代码的样子,它能很好地工作,但大问题是它会耗尽我的电池?


1
“我尝试使用postDelayed但它没有起作用?” - 这并没有解释任何问题。如果没有更多的代码和logcat输出来显示异常,回答你的问题就不容易了。 - Squonk
@MisterSquonk 发布了我的整个代码.. - Shan
3
当然会消耗你的电池。你正在获取网络内容,等待100毫秒后再获取。这对你的电池不利,并且在你收到手机账单时可能非常昂贵。 - CommonsWare
以下任何方法都无法工作,我该怎么办??我想每2分钟或5分钟获取一次网页内容。 - Shan
9个回答

79

如果您想每隔 X 秒启动某个操作,可以使用 Handler。Handler 很好用,因为您不需要额外的线程来跟踪何时触发事件。以下是一个简短的代码片段:

private final static int INTERVAL = 1000 * 60 * 2; //2 minutes
Handler mHandler = new Handler();

Runnable mHandlerTask = new Runnable()
{
     @Override 
     public void run() {
          doSomething();
          mHandler.postDelayed(mHandlerTask, INTERVAL);
     }
};

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

void stopRepeatingTask()
{
    mHandler.removeCallbacks(mHandlerTask);
}

请注意,doSomething 不应该花费太长时间(比如在 UI 中更新音频播放的位置)。如果它可能需要一些时间(比如下载或上传到网络),那么你应该使用ScheduledExecutorServicescheduleWithFixedDelay函数。


我已经编辑了你的代码,请记住2000毫秒等于2秒;120000毫秒等于2分钟。 - Jorgesys
小错误:应该是m_handler.removeCallbacks而不是m_handler.removeCallback。 - tarkeshwar
除了@tarkeshwar提到的类型之外,还有另一种类型存在。在创建可运行程序的末尾应添加--;--。 - tony9099
这个处理程序是使用AsyncTask实现的吗?还是你在说我们应该删除AsyncTask,改用handlers? - sorry_I_wont
我应该把上面的代码放在哪里?在 onCreate 里面吗? - mcExchange
显示剩余8条评论

32

使用HandlerPostDelayed

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    public void run() {
        readWebpage();
        handler.postDelayed(this, 120000); //now is every 2 minutes
    }
 }, 120000); //Every 120000 ms (2 minutes)

3
请注意,postDelayed() 方法也是 View 上的一个方法,因此如果您已经有一个小部件可用,那么您不需要使用 Handler 来实现延迟操作。 - CommonsWare
9
并不是每2分钟都会运行一次,它只会在延迟2分钟后运行一次。 - inazaruk

7
您可以使用TimerTask代替AsyncTask。
例如:
Timer myTimer = new Timer("MyTimer", true);
myTimer.scheduleAtFixedRate(new MyTask(), ASAP, TWO_MINUTES);


private class MyTask extends TimerTask {

    public void run(){
      readWebPage();
    }

}

2
当手机进入睡眠模式以节省电量时,可能会在2分钟内发生。这种情况下,Handler.postDelayed() 可能会错过预定的时间。对于这样的活动,您应该使用 AlarmManager,并使用 PowerManager 获取锁以防止在运行 AsyncTask 时返回睡眠状态。
请参阅我的帖子,并查看代码示例here 此外,您可能需要阅读Scheduling Repeating Alarms

2

我建议使用Handler#postDelayed(Runnable)。需要注意的是,这个方法只在你的应用程序运行时(可能在后台)才会工作,但如果用户手动关闭它或者Android内存不足,它将停止工作并且以后也不会重新启动-为此,您需要使用服务。

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        handler.postDelayed(this, 2 * 60 * 1000); // every 2 minutes
        /* your code here */
    }
}, 2 * 60 * 1000); // first run after 2 minutes

这段代码将会等待2分钟,执行你的代码,然后每隔2分钟重复这个过程。但是如果你想让它在第一次立即运行 - 然后开始等待执行循环,可以使用:

final Handler handler = new Handler();
 /* your code here */
new Runnable() {
    @Override
    public void run() {
        handler.postDelayed(this, 2 * 60 * 1000); // every 2 minutes
         /* and also here - your code */
    }
}.run(); 

或者,如果你的代码不仅仅是一个方法(readWebsite()在这里),并且你不想重复它:

final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        handler.postDelayed(this, 2 * 60 * 1000); // every 2 minutes
         /* your longer code here */
    }
}, 0); // first run instantly

(^ 这个示例与第一个示例类似,但在第一次运行之前有0ms的延迟,而不是2分钟)

(这个答案基于@Devashish Mamgain的答案,但我添加了太多细节以至于无法编辑,所以我必须添加一个新的)


我现在正在使用服务 :) ,而这个问题是5年前的 :)。 - Shan

0

如果要执行多个消息(Runnables),则应使用Looper类,该类负责在线程中创建队列。例如,在编写从互联网下载文件的应用程序时,我们可以使用Looper类将要下载的文件放入队列中。这将帮助您在Android中执行异步任务...

HandlerThread hThread = new HandlerThread("HandlerThread");
  hThread.start();
  Handler handler = new Handler(hThread.getLooper());
  final Handler handler1 = new Handler(hThread.getLooper());
  final long oneMinuteMs = 60 * 1000;

  Runnable eachMinute = new Runnable() { 
   @Override
   public void run() {
    Log.d(TAG, "Each minute task executing");
    handler1.postDelayed(this, oneMinuteMs);
    sendPostRequest();
   }
  };
 // sendPostRequest();
  // Schedule the first execution
  handler1.postDelayed(eachMinute, oneMinuteMs);

0
你可以使用Handler和TimerTask来处理时间。
  final Handler handler = new Handler();
        Timer timer = new Timer();
        TimerTask backtask = new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    public void run() {
                        try {
                            //To task in this. Can do network operation Also
                            Log.d("check","Check Run" );
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                        }
                    }
                });
            }
        };
        timer.schedule(backtask , 0, 20000); //execute in every 20000 ms*/

您可以使用“check”标签名称检查logcat以验证是否正在运行


0
尝试扩展Thread类,将睡眠时间设置为2000毫秒,并将调用放入run方法中。这样应该就可以了。

-14
你可以在 AsyncTask 中运行一个循环,在执行任务之间暂停两秒钟。就像这样:
protected Result doInBackground (Params... params) {
    while (!interrupted) {
        doWork();
        Thread.sleep(2000);
    }
}

5
在一个无限循环中运行 doInBackground() 方法真的不是一个好主意。理想情况下,使用 AsyncTask 应该是一次性操作,不应该长时间运行。 - Squonk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接