安排将来要执行的事件(Android方式的Cron Job)

我有一些曾经失去相关性的日期,并且应该计算DB中这些字段的新日期,我知道我可以利用AlarmManager类,但是我对此有一些担忧:

1)注意:从API 19(KITKAT)开始,警报传递不准确:操作系统将移动警报以最小化唤醒和电池使用。 有新的API支持需要严格交付保证的应用程序; 请参阅setWindow(int,long,long,PendingIntent)和setExact(int,long,PendingIntent)。 targetSdkVersion早于API 19的应用程序将继续查看先前在请求时准确传递所有警报的行为。

那么我是否需要单独编写这两种情况的代码,或者如果我的目标是kitkat,那么它也适用于旧版本吗? 此外,由于我的代码执行时间紧迫,比如在某个日期的午夜12点之后,我的数据失去了相关性,如何克服警报的转移。

2)在设备处于hibernate状态时保留已注册的警报(如果设备在此期间关闭,可以选择将设备唤醒),但如果设备关闭并重新启动,则会清除设备。

2.1)在应用程序的清单中设置RECEIVE_BOOT_COMPLETED权限。 这允许您的应用程序接收系统完成引导后广播的ACTION_BOOT_COMPLETED (仅当用户已经至少一次启动应用程序时才有效)

2.1.1)如果我在12处设置了警报,则与此警报相关的服务将在12时触发,现在当我重新启动设备时,“12”时间已经过去,警报将立即再次触发并且服务会再次被召唤?

在重启时我需要实现什么机制才能在特定时间坚持我的代码执行策略? 如果用户未启动我的应用,如何设置闹钟?

第三件事是,如果我的应用程序被卸载,我想清除我的代码设置的所有警报,我如何在卸载应用程序时收听?

另外我想知道,我的应用程序非常关键,我的数据库中的值每晚12点都会过时,而我正在更新应用程序,如果用户选择在12时使用我的应用程序,结果会是什么使用服务来更新它并在后台运行?

编辑:到目前为止我尝试过:

我有一个数据库,其中记录在午夜过时,在12:00时说得很清楚。 我调用了一个警报管理器(在一个测试项目中,因为我喜欢隔离问题代码)来启动服务。 我还在设备上获得了PARTIAL_WAKE_LOCK,以便正确完成我庞大的数据库操作。 我还实现了一个线程来完成我耗时的任务。 以下是我的MainActivity类,我在12处调用它来启动警报(随机时间用于测试目的):

public class MainActivity extends Activity { private AlarmManager alarmMgr; private PendingIntent alarmIntent; BroadcastReceiver br; TextView t; int sum; public void setSum(int s){ sum = s; // t = (TextView)findViewById(R.id.textView1); // t.setText(sum); System.out.println("In Set Sum"+s); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setup(); t = (TextView)findViewById(R.id.textView1); ComponentName receiver = new ComponentName(getApplicationContext(), SampleBootReceiver.class); PackageManager pm = getApplicationContext().getPackageManager(); pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 17); calendar.set(Calendar.MINUTE, 05); // Particular minute calendar.set(Calendar.SECOND, 0); alarmMgr = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE); alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000*60*60*24, alarmIntent); } public void setup() { br = new BroadcastReceiver() { @Override public void onReceive(Context c, Intent i) { Toast.makeText(c, "Rise and Shine!", Toast.LENGTH_LONG).show(); //Invoke the service here Put the wake lock and initiate bind service t.setText("Hello Alarm set"); startService(new Intent(MainActivity.this, MyService.class)); stopService(new Intent(MainActivity.this, MyService.class)); } }; registerReceiver(br, new IntentFilter("com.testrtc") ); alarmIntent = PendingIntent.getBroadcast( this, 0, new Intent("com.testrtc"),0 ); alarmMgr = (AlarmManager)(this.getSystemService( Context.ALARM_SERVICE )); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } } 

这是我的SampleBootReceiver类,以便检查重新启动并在重新启动后再次设置警报,我不确定它是否按预期工作。 我找不到测试这是否正常工作的方法,但我收到关于完成启动的Toast消息。

 public class SampleBootReceiver extends BroadcastReceiver { private AlarmManager alarmMgr; private PendingIntent alarmIntent; BroadcastReceiver br; TextView t; MainActivity main; @Override public void onReceive(Context context, Intent intent) { main= new MainActivity(); if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { Toast.makeText(context, "Hello from Bootloader", 10000).show(); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 15); calendar.set(Calendar.MINUTE, 50); // Particular minute calendar.set(Calendar.SECOND, 0); alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000*60*60*24, alarmIntent); context.getApplicationContext().registerReceiver(br, new IntentFilter("com.testrtc") ); alarmIntent = PendingIntent.getBroadcast( context.getApplicationContext(), 0, new Intent("com.testrtc"), 0 ); alarmMgr = (AlarmManager)(context.getApplicationContext().getSystemService( Context.ALARM_SERVICE )); } } } 

以下是我的服务类,不确定我在onStartCommand方法中所做的返回:

 public class MyService extends Service { int a = 2; int b = 2; int c = a+b; public MainActivity main = new MainActivity(); public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { Toast.makeText(this, "The new Service was Created", Toast.LENGTH_LONG).show(); } @Override public int onStartCommand(Intent i, int flags , int startId){ WakeLock wakeLock = null; try{ PowerManager mgr = (PowerManager)getApplicationContext().getSystemService(Context.POWER_SERVICE); wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"); wakeLock.acquire(); Toast.makeText(this, " Service Started", Toast.LENGTH_LONG).show(); new Thread(new Runnable() { public void run(){ //Will be substituted with a time consuming long task. main.setSum(c); } }).start(); }catch(Exception e){ System.out.println(e); }finally{ wakeLock.release(); } return 1; } @Override public void onDestroy() { Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show(); } } 

同样在上面,我想知道我开始的线程是否会与我如何获取唤醒锁。 如果我可以使用异步任务并在onPostExecute中释放唤醒锁?

最后这是我的清单:

                       

这是我的日志Cat重启后,有很多日志消息,但我发现这些与应用程序有关,它们包含th epackage名称:

 01-22 15:18:35.652: V/ActivityManager(419): getTasks: max=1, flags=0, receiver=null 01-22 15:18:35.652: V/ActivityManager(419): com.xxx.xxx/.MainActivity: task=TaskRecord{425c58f0 #5 A com.xxx.xxx U 0} 01-22 15:18:35.653: V/ActivityManager(419): We have pending thumbnails: null 

更多问题:我应该在哪里设置闹钟,如果我在启动画面的onCreate中执行此操作,则每次应用程序启动时都会调用它,可能会覆盖较旧的值。

其次我希望在我的服务运行时获取数据库的锁定,如果在这个时候用户试图打开我的应用程序我该怎么办? (随着数据的更新,我没有任何东西可以展示)。

在上面的代码中,我仍然发现重启后注册警报的问题。

1)要在准确的时间处理警报,您有2个选项:a)将最低SDK级别设置为18而不是19.这将使您的应用程序在确切的时间在kitkat上工作b)使用setExact()方法告诉Kitkat保持您在指定的确切时间发出警报来源: http : //developer.android.com/about/versions/android-4.4.html

2)启动完成通知是最好的方法。 您可以设置广播接收器以在重新启动时获取通知。 您可以将警报存储在数据库中并在重新启动时检索。

2.1)做一些用户不希望你做的事情是一种可怕的编程习惯,即即使用户没有打开应用程序也要设置闹钟。

3)只要您不在SD卡上创建文件,卸载应用程序后将删除所有应用程序数据

4)您应该在写入或读取数据时锁定/解锁数据以解决您的12AM问题。 如果数据被锁定,则在用户提交事务之前不会受到影响。 如果您使用的是SQLite,可以从http://www.sqlite.org/lockingv3.html获取更多相关信息

我认为,您可以编写类似于下面的Service (这将每5分钟完成一次),并从侦听BOOT_COMPLETED状态的BroadcastReceiver启动Service

 public class YourService extends IntentService { public YourService() { super("YourService"); } public YourService(String name) { super(name); } private static Timer timer = new Timer(); private class mainTask extends TimerTask { public void run() { // TASK WHATEVER YOU WANT TO DO } } public void onDestroy() { super.onDestroy(); } @Override protected void onHandleIntent(Intent intent) { timer.scheduleAtFixedRate(new mainTask(), 0, 300000); // 5 minutes } }