2014-10-01 68 views
1

我在Android的闹钟管理器有一些问题。所以我试图做的是设置闹钟,重复每天12.01AM左右运行数据库插入。安卓闹钟管理器设置重复在特定时间

Calendar calendar = Calendar.getInstance(); 
    calendar.setTimeInMillis(System.currentTimeMillis()); 
    calendar.set(Calendar.HOUR_OF_DAY, 0); 
    calendar.set(Calendar.MINUTE, 1); 
     notificationCount = notificationCount + 1; 
     AlarmManager mgr = (AlarmManager) context 
       .getSystemService(Context.ALARM_SERVICE); 
     Intent notificationIntent = new Intent(context, 
       ReminderAlarm.class); 

     notificationIntent.putExtra("NotifyCount", notificationCount); 
     PendingIntent pi = PendingIntent.getBroadcast(context, 
       notificationCount, notificationIntent, 
       PendingIntent.FLAG_UPDATE_CURRENT); 
     mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, 
       calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi); 

所以基本上我已经想出了这些代码。然而,警报管理器在我设置它的那一分钟后再次执行。

假设我在2014年10月10日5.48PM运行应用程序。我想在每天将onReceive设置在12.01AM左右后运行数据库插入。但不知何故,警报管理器在执行时间为2014年1月10日下午5点49分,这是我设置后一分钟后停止工作。

我想知道我错误地做了哪一部分。

在此先感谢。

编辑

周期性类 对于这个类,就会触发报警经理日常和传递变量一起为DB插入提醒报警类别。

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.recurring); 
    context = this; 
    buildListView(); 
    if(!alarmInitialized(this)) { 
     scheduleAlarms(this); 
    } 
} 

// And the few methods you suggested to schedule the alarm 
public static void scheduleAlarms(Context context) { 
    Calendar calendar = Calendar.getInstance(); 
    if (hasRunnedToday(context)) { // if the alarm has run this day 
     calendar.add(Calendar.DATE, 1); // schedule it to run again starting 
             // tomorrow 
    } 

    long firstRunTime = calendar.getTimeInMillis(); 
    AlarmManager mgr = (AlarmManager) context 
      .getSystemService(Context.ALARM_SERVICE); 
    Intent notificationIntent = new Intent(context, ReminderAlarm.class); 
    PendingIntent pi = PendingIntent.getActivity(context, 0, 
      notificationIntent, 0); 
    mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstRunTime, 
      AlarmManager.INTERVAL_DAY, pi); 

    ComponentName receiver = new ComponentName(context, BootReceiver.class); 
    PackageManager pm = context.getPackageManager(); 

    pm.setComponentEnabledSetting(receiver, 
      PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 
      PackageManager.DONT_KILL_APP); 
} 

BootReceiver类

public void onReceive(Context context, Intent i) { 
    if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { 
     Recurring.scheduleAlarms(context); 
    } 
} 

ReminderAlarm类 基本上这个类,它只是抓住从周期性类传递的变量,并执行DB插入。我确实插入了一些Toast.makeText来测试它是否正在检索,但通过测试没有运气。

public class ReminderAlarm extends BroadcastReceiver { 
private NotificationManager mNotificationManager; 
private Notification notification; 

@Override 
public void onReceive(Context context, Intent intent) { 
    String recurID = null; 
    String recurStartDate = null; 
    String currentDate = null; 
    String description = null; 
    String type = null; 
    String amount = null; 
    String categoryName = null; 
    String frequencyStr = null; 
    String nextPaymentDate = null; 
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); 

    DatabaseAdapter mDbHelper = new DatabaseAdapter(context); 
    mDbHelper.createDatabase(); 
    mDbHelper.open(); 
    RecurringController rc = new RecurringController(mDbHelper.open()); 
    ArrayList<RecurringModel> recur_list = rc.getAllRecurring(); 

    // THIS PART TO GET DATA FROM DATABASE 
    for (int i = 0; i < recur_list.size(); i++) { 
     recurID = recur_list.get(i).getRecurringID(); 
     recurStartDate = recur_list.get(i).getRecurringStartDate(); 
     currentDate = dateFormat.format(new Date()); 
     description = recur_list.get(i).getRecurringDesc(); 
     type = recur_list.get(i).getRecurringType(); 
     amount = Float.toString(recur_list.get(i).getRecurringAmount()); 
     categoryName = recur_list.get(i).getCategoryID(); 
     frequencyStr = recur_list.get(i).getFrequency(); 

     Toast.makeText(context, 
        description, Toast.LENGTH_LONG) 
        .show(); 
     Toast.makeText(context, 
        recurStartDate Toast.LENGTH_LONG) 
        .show(); 

     Calendar cal = Calendar.getInstance(); 
     try { 
      cal.setTime(dateFormat.parse(recurStartDate)); 
      if (frequencyStr.equals("Daily")) { 
       cal.add(Calendar.DAY_OF_MONTH, 1); 
       nextPaymentDate = dateFormat.format(cal.getTimeInMillis()); 
       cal.add(Calendar.DAY_OF_MONTH, -1); 
      } else if (frequencyStr.equals("Weekly")) { 
       cal.add(Calendar.WEEK_OF_YEAR, 1); 
       nextPaymentDate = dateFormat.format(cal.getTimeInMillis()); 
       cal.add(Calendar.WEEK_OF_YEAR, -1); 
      } else if (frequencyStr.equals("Monthly")) { 
       cal.add(Calendar.MONTH, 1); 
       nextPaymentDate = dateFormat.format(cal.getTimeInMillis()); 
       cal.add(Calendar.MONTH, -1); 
      } else if (frequencyStr.equals("Yearly")) { 
       cal.add(Calendar.YEAR, 1); 
       nextPaymentDate = dateFormat.format(cal.getTimeInMillis()); 
       cal.add(Calendar.YEAR, -1); 
      } 
     } catch (ParseException e) { 
      e.printStackTrace(); 
     } 

     // If dates match then execute the SQL statements 
     if (currentDate.equals(nextPaymentDate)) { 
      // mDbHelper.createDatabase(); 
      // mDbHelper.open(); 
      TransactionRecModel trm = new TransactionRecModel(); 
      CategoryController cc = new CategoryController(mDbHelper.open()); 

      trm.setDate(currentDate); 
      trm.setTransDescription(description); 
      trm.setType(type); 
      trm.setAmount(Float.parseFloat(amount)); 

      // Get the categoryID based on categoryName 
      String catID = cc.getCatIDByName(categoryName); 
      trm.setCategory(catID); 

      // Check if the recurring record exists before insert new 
      // transaction record 
      boolean recurExist = rc.checkRecurExist(recurStartDate, 
        description, catID); 
      if (recurExist == true) { 
       TransactionRecController trc = new TransactionRecController(
         mDbHelper.open()); 
       // Check if the transaction record exists to prevent 
       // duplication 
       boolean moveNext = trc.checkTransExist(trm); 
       if (moveNext == false) { 

        if (trc.addTransactionRec(trm)) { 
         // Update recurring start date after insertion of 
         // transaction 
         RecurringModel rm = new RecurringModel(); 
         rm.setRecurringID(recurID); 
         rm.setRecurringStartDate(currentDate); 

         if (rc.updateRecurringDate(rm)) { 
          mNotificationManager = (NotificationManager) context 
            .getSystemService(Context.NOTIFICATION_SERVICE); 
          PendingIntent contentIntent = PendingIntent 
            .getActivity(
              context, 
              Integer.parseInt(intent 
                .getExtras() 
                .get("NotifyCount") 
                .toString()), 
              new Intent(), 0); 
          notification = new Notification(
            R.drawable.ic_launcher, "Notification", 
            System.currentTimeMillis()); 
          notification.setLatestEventInfo(context, 
            description, nextPaymentDate, 
            contentIntent); 
          mNotificationManager 
            .notify(Integer.parseInt(intent 
              .getExtras().get("NotifyCount") 
              .toString()), notification); 
          mDbHelper.close(); 
         } 
        } 
       } 
      } 
      mDbHelper.close(); 
     } 
    } 
    mDbHelper.close(); 
    Recurring.updateAlarmLastRun(context); 
} 
} 

我在您建议的部分中添加了这部分代码,以安排警报调用BootReceiver类。然后,从BootReceiver类,我会打电话回周期性类和提醒报警类别:

ComponentName receiver = new ComponentName(context, BootReceiver.class); 
    PackageManager pm = context.getPackageManager(); 

    pm.setComponentEnabledSetting(receiver, 
      PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 
      PackageManager.DONT_KILL_APP); 
+0

**” ......报警经理执行在2014年1月10日下午5点49分是在一分钟后我将它和它停止工作。“**您将”Calendar.HOUR_OF_DAY“设置为0,从而将时间倒退。这会立即触发警报,直到第二天00:01才会再次触发。 – Squonk 2014-10-01 10:11:27

+0

@Squonk那么你有什么想法来解决这个问题吗?因为从我的研究中,我认为这样做能够在特定时间触发警报。 – 2014-10-01 10:13:41

+0

@Squonk那么我把这些代码放在哪里?你介意把整个部分作为答案吗? – 2014-10-01 10:24:52

回答

5

的问题是在calendar.getTimeInMillis()

mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, 
      calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pi); 

的第二个参数setInexactRepeating引述商务部

triggerAtMillis使用适当的时钟(取决于报警类型),报警应首先关闭的毫秒时间。这是不准确的:警报在此时间之前不会触发,但在第一次调用警报之前可能会有几乎整个警报间隔的延迟。

这意味着它设置之后,因为

calendar.setTimeInMillis(System.currentTimeMillis()); 
calendar.set(Calendar.HOUR_OF_DAY, 0); 
calendar.set(Calendar.MINUTE, 1); 

如果您wan't报警的第一次运行,第二天做 日历将aproximally首次运行一分钟。添加(日历。日期,1);`

至于它停止工作,你重新启动德设备? AlarmCalendar报警不会坚持到设备重新启动,你可以注册一个BroadcastReceiver接收BOOT_COMPLETED事件和注册警报再次检查 does Alarm Manager persist even after reboot?

更新:按照您的要求在这里查看您的代码后,一些帮助

在您BOOT_COMPLETED接收机类:

public void onReceive(Context context, Intent i) { 
    if (i.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { 
     ReminderAlarm.scheduleAlarms(this); 
    } 
} 

在你ReminderAlarm CLA SS

protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.recurring); 

if(!alarmInitialized(this) { 
    scheduleAlarms(this); 
} 

}

public static void scheduleAlarms(Context context) { 

    Calendar calendar = Calendar.getInstance(); 

    if(hasRunnedToday(context)) {  //if the alarm has run this day 
     calendar.add(Calendar.DATE, 1); //schedule it to run again starting tomorrow 
    } 

    long firstRunTime = calendar.getTimeInMillis(); 

    AlarmManager mgr = (AlarmManager) context 
      .getSystemService(Context.ALARM_SERVICE); 
    Intent notificationIntent = new Intent(context, ReminderAlarm.class); 
    PendingIntent pi = PendingIntent.getActivity(context, 0, 
      notificationIntent, 0); 

    mgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, 
      firstRunTime, AlarmManager.INTERVAL_DAY, pi); 
} 

public static boolean alarmInitialized(Context context) { 
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE); 

    long alarmLastRun = preferences.getLong("AlarmLastRun", -1); 


    return alarmLastRun != -1; 

} 

public static void updateAlarmLastRun(Context context) { 
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE); 


    preferences.edit() 
      .putLong("AlarmLastRun", new Date().getTime()) 
     .apply(); 
} 

public static boolean hasRunnedToday(Context context) { 
    SharedPreferences preferences = context.getSharedPreferences("alarm_prefs", MODE_PRIVATE); 

    long alarmLastRun = preferences.getLong("AlarmLastRun", -1); 

    if(alarmLastRun == -1) { 
     return false; 
    } 

    //check by comparing day, month and year 
    Date now = new Date(); 
    Date lastRun = new Date(alarmLastRun); 


    return now.getTime() - lastRun.getTime() < TimeUnit.DAYS.toMillis(1); 
} 

您的每一个提醒类报警运行,你应该叫updateAlarmLastRun更新警报已经对最近一次运行时间,这是必要的,因为报警可能会日程是运行一天,并且用户在警报运行之前重新启动设备,在这种情况下,我们不希望 使用calendar.add(Calendar.DATE, 1);,因为那样会跳过一天。

在您Manifest.xml

<receiver android:name=".BootReceiver" android:enabled="true" android:exported="false" android:permission="android.permission.RECEIVE_BOOT_COMPLETED"> 
    <intent-filter> 
     <action android:name="android.intent.action.BOOT_COMPLETED" /> 
    </intent-filter> 
    </receiver> 

注:

  1. 你不应该做context = this如果上下文是一个类字段,因为对象持有其领域contextcontext字段的引用持有参考到会泄漏的对象
  2. 您的Receiver'onReceive`没有额外设置,您假设拥有像“notificationCount”onRec系统在您的设备完成启动时由系统提供。
  3. 一旦报警跑致电updateAlarmLastRun

希望任何这有助于

+0

是的,我添加了代码,以便在重新启动时警报仍然会持续。但我应该在哪里添加instance.add()? – 2014-10-09 11:35:47

+0

我的坏我的意思calendar.add我已经更新了awnser – forcewill 2014-10-09 11:39:16

+0

所以我应该在我的两个类中添加该行?你能帮我检查一下我编辑过的部分吗? – 2014-10-09 11:42:49

相关问题