2014-10-01 67 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

相關問題