在Android中计划重复任务

我正在devise一个应用程序,只要应用程序处于前台状态,该应用程序就会反复发送状态到专用服务器。

在我的networkingsearch中,我看到了一些不同的方法,并想知道做这件事的最好方法是什么。

安排服务器调用的最佳方式是什么?

我看到的选项是:

  1. 定时器 。

  2. ScheduledThreadPoolExecutor 。

  3. 服务 。

  4. BroadcastReciever与AlarmManager 。

你怎么看?

编辑:
我需要这个的原因是基于聊天的应用程序,将所有的用户操作发送到远程服务器。
即用户正在input消息,用户正在阅读消息,用户在线,用户正在离线等。

这意味着每隔一段时间,我都需要向服务器发送我正在做的事情,因为我和其他人打开了一个聊天室,他们需要知道我在做什么。

类似于whatsapp消息反馈机制: 消息看起来交付

编辑#2:
现在应该几乎总是通过JobScheduler API(或针对较低API的FirebaseJobDispatcher )安排定期任务,以防止电池耗尽问题,这可以在Android培训的生命周期部分中阅读

我不确定,但根据我的知识,我分享了我的观点。 如果我错了,我总是接受最好的答案。

报警pipe理器

只要警报接收器的onReceive()方法正在执行,警报pipe理器就会保持CPU唤醒锁。 这可以保证手机在处理完广播之前不会睡觉。 一旦onReceive()返回,警报pipe理器释放这个唤醒锁。 这意味着,只要您的onReceive()方法完成,手机会在某些情况下进入hibernate状态。 如果您的警报接收器调用了Context.startService() ,那么在请求的服务启动之前,手机可能会睡眠。 为了防止这种情况发生,您的BroadcastReceiverService将需要实施一个单独的唤醒locking策略,以确保电话继续运行,直到服务可用。

注意:“报警pipe理器”适用于希望在特定时间运行应用程序代码的情况,即使您的应用程序当前未在运行。 对于正常的定时操作(滴答,超时等),使用Handler更容易,效率更高。

计时器

 timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { synchronized public void run() { \\ here your todo; } }}, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1)); 

Timer有一些缺点,由ScheduledThreadPoolExecutor解决。 所以这不是最好的select

ScheduledThreadPoolExecutor

您可以使用java.util.TimerScheduledThreadPoolExecutor (首选)来安排在后台线程上定期执行的操作。

以下是使用后者的示例:

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

所以我更喜欢ScheduledExecutorService

但是也要考虑一下,如果更新将在应用程序运行时发生,则可以使用Timer ,如其他答案中所build议的,或者更新的ScheduledThreadPoolExecutor 。 如果您的应用程序即使在没有运行时也会更新,那么您应该使用AlarmManager

报警pipe理器用于您希望在特定时间运行应用程序代码的情况,即使您的应用程序当前不在运行。

请注意,如果您计划在closures应用程序时进行更新,则每十分钟一次就会频繁发生,因此可能会耗费太多电量。

计时器

正如在javadocs中所提到的,最好使用ScheduledThreadPoolExecutor。

的ScheduledThreadPoolExecutor

当您的用例需要多个工作线程并且hibernate间隔很小时使用此类。 多么小 ? 那么,我会说大约15分钟。 AlarmManager启动调度间隔,似乎表明对于较小的睡眠间隔,可以使用此类。 我没有数据来支持最后的声明。 这是一个预感。

服务

您的服务可以随时由VMclosures。 不要将服务用于重复性任务。 重复执行的任务可以启动服务,这完全是另一回事。

BroadcastReciever与AlarmManager

对于更长的睡眠间隔(> 15分钟),这是要走的路。 AlarmManager已经有了常量( AlarmManager.INTERVAL_DAY ),表明它可以在最初被调度后几天触发任务。 它也可以唤醒CPU来运行你的代码。

您应该根据您的时间和工作线程需要使用这些解决scheme之一。

我意识到这是一个古老的问题,已经得到了答复,但这可以帮助某人。 在你的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. 

引用计划重复警报 – 了解权衡文档:

触发应用程序生命周期之外的操作的常见scheme是将数据与服务器同步。 在这种情况下,您可能会试图使用重复闹钟。 但是,如果您拥有托pipe应用数据的服务器,则将Google Cloud Messaging(GCM)与同步适配器一起使用是比AlarmManager更好的解决scheme。 同步适配器为您提供与AlarmManager相同的调度选项,但它为您提供了更大的灵活性。

因此,基于此,安排服务器调用的最佳方式是使用Google Cloud Messaging(GCM)和同步适配器 。

我已经创build了用户想要重复执行的任务,并添加了Custom 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); }}); } } 

}

BroadcastRecieverAlarmManager是安排一个服务器调用android环境的最佳方式。

也许这不是你的问题的答案,而是你的应用结构的build议。 对于我来说,使用节点JS和SOCKET.IO来处理聊天等应用要容易得多。 因为它是实时的,所以你不需要每隔一定的时间询问服务器。 在那里你可以阅读更多关于SOCET IO – http://socket.io/