2014-01-23 68 views
1

我想在我的Android應用中實現「每日提醒」功能,應該在設定的時間每天觸發一次。我嘗試的第一個實現是爲大多數人工作的,但是一些用戶子集(包括至少一個在三星的Android 4.3上運行的人)報告說,警報以比它應該更頻繁的方式觸發,例如,每10分鐘一次,每次他們打開應用程序,一般都很煩人。Android的每日鬧鈴發射太頻繁或只有一次

這裏的報警的啓用:

Intent myIntent = new Intent(ctx, AlarmReceiver.class); 
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, 0, myIntent,0); 

AlarmManager alarmManager = (AlarmManager)ctx.getSystemService(Service.ALARM_SERVICE); 
alarmManager.cancel(pendingIntent); 
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, sched, 
       AlarmManager.INTERVAL_DAY, 
       pendingIntent); 

再有就是這個AlarmReceiver類:

public class AlarmReceiver extends BroadcastReceiver { 

    @Override 
    public void onReceive(Context context, Intent intent) { 
     // TODO Auto-generated method stub 

      Intent service1 = new Intent(context, AlarmService.class); 
      context.startService(service1); 
    } 

} 

這是登記在AndroidManifest接收器:<receiver android:name=".AlarmReceiver"/>

最後還有的AlarmService ,它看起來像這樣:

public class AlarmService extends Service { 

    @Override 
    public IBinder onBind(Intent arg0) { 
     // TODO Auto-generated method stub 
     return null; 
    } 


    @Override 
    public void onCreate() 
    { 
     // TODO Auto-generated method stub 
     super.onCreate(); 
    } 

    @SuppressWarnings("static-access") 
    @Override 
    public void onStart(Intent intent, int startId) 
    { 
     super.onStart(intent, startId); 

     Log.v("pm", "about to notify"); 

     Intent intent1 = new Intent(this.getApplicationContext(), MainActivity.class); 
     intent1.setAction(Intent.ACTION_MAIN); 
     intent1.addCategory(Intent.CATEGORY_LAUNCHER); 
     //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP); 

     PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT); 

     Notification notification = new Notification.Builder(this.getApplicationContext()) 
             .setContentTitle("My App") 
             .setContentText("Don't forget that thing!") 
             .setSmallIcon(R.drawable.ic_launcher) 
             .setWhen(System.currentTimeMillis()) 
             .setContentIntent(pendingNotificationIntent) 
             .getNotification();      

     notification.flags |= Notification.FLAG_AUTO_CANCEL; 
     notification.defaults |= Notification.DEFAULT_SOUND; 
     notification.defaults |= Notification.DEFAULT_VIBRATE; 

     NotificationManager nManager = 
       (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
     nManager.notify(0, notification); 
    } 

    @Override 
    public void onDestroy() 
    { 
     // TODO Auto-generated method stub 
     super.onDestroy(); 
    } 
} 

但是,正如我所說,人們報告說這每十分鐘就會發射一次!所以我嘗試將AlarmService更改爲一個較不被棄用的實現,但在這個過程中,現在人們說它只會觸發一次,然後再也不會!

我換成onStart這個:

@Override 
public int onStartCommand(Intent intent, int flags, int startId) 
{ 
     Log.v("pm", "about to notify"); 

    if (intent != null) { 
     Intent intent1 = new Intent(this.getApplicationContext(), MainActivity.class); 
     intent1.setAction(Intent.ACTION_MAIN); 
     intent1.addCategory(Intent.CATEGORY_LAUNCHER); 
     //intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP); 

     PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this.getApplicationContext(),0, intent1,PendingIntent.FLAG_UPDATE_CURRENT); 

     Notification notification = new Notification.Builder(this.getApplicationContext()) 
             .setContentTitle("My App") 
             .setContentText("Don't forget that thing!") 
             .setSmallIcon(R.drawable.ic_launcher) 
             .setWhen(System.currentTimeMillis()) 
             .setContentIntent(pendingNotificationIntent) 
             .getNotification();      

     notification.flags |= Notification.FLAG_AUTO_CANCEL; 
     notification.defaults |= Notification.DEFAULT_SOUND; 
     notification.defaults |= Notification.DEFAULT_VIBRATE; 

     NotificationManager nManager = 
       (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 
     nManager.notify(0, notification); 
    } else { 
     Log.v("pm", "Null Intent"); 
    } 

    return START_STICKY; 
} 

既然不能複製我的設備原來的問題,這是一個有點難以測試!我的兩個理論是:

  1. 的問題在於AlarmReceiver,喜歡它應該不會是啓動一個全新的服務,但做一些與現有的服務
  2. 我不應該去在排除空intent值我onStartCommand功能

我只是有點緊張,嘗試2號以防萬一它導致人們的設備再次惹惱他們!

+0

稱爲如果你能等待,這幾天我米工作在一個雙定時器(1個鬧鐘是每月和1個鏡頭,另一個是每天在固定的時間和重複)。問題是,我目前正在關閉工作,並在幾個小時之前不會回家......但我有一個接近工作的解決方案(只是它不能在重新啓動後繼續工作 - 仍在工作)。 –

+1

我越來越想知道爲什麼我的AlarmReceiver創建服務,而不是直接顯示通知... – andygeers

回答

6

這裏的報警器是如何啓用

注意,這將是不準確的在Android 4.4或以上版本,即使您正在使用setRepeating(),一旦你提高你的android:targetSdkVersion到19或更高。

再有就是這個AlarmReceiver類

這不會是一個_WAKEUP風格報警可靠。設備在startService()呼叫和您的服務實際上有機會做某事之間入睡是非常有可能的。如果您要使用代理到服務模式,請爲use WakefulBroadcastReceivermy WakefulIntentService代表_WAKEUP-樣式警報。

但在這個過程中,現在人們都說它每天只發一次!

既然這是你想要的,我會認爲這是一件好事。

我取代在onStart這個:

我不知道爲什麼你使用的是Service代替IntentService。無論如何,請在onStartCommand()方法的底部撥打stopSelf(),這樣服務就會消失。這項服務完成後沒有理由繼續運行。另外,用START_NOT_STICKY代替START_STICKY

而且,如果這是你想要的服務做的工作,你可以放棄完全的服務和移動你的膽量onStartCommand()進入BroadcastReceiveronReceive()

當工作花費太長的時間來冒險捆綁主應用程序線程(例如,> 1ms)時,會使用委託工作從接收方到服務的模式...但您的服務需要後臺線程,你的缺乏。由於我期望您的代碼在執行時間內小於1毫秒,因此您可以在onReceive()中執行此操作並簡化您的應用程序,您將不再需要單獨的Service或我之前提到的任何Wakeful*

的問題在於AlarmReceiver,喜歡它應該不會首發了全新的服務,但這樣做與現有的服務

東西如果只運行每天一次,也最好不要是「現有服務」。您不需要有一個正在運行的進程,捆綁系統RAM,只需等待時鐘打勾即可。

我不應該打擾我onStartCommand功能不包括空意圖值

你會得到一個nullIntent如果:

  • 服務完成onStartCommand()爲之前,您的進程被終止撥打startService()

  • 您的服務已成功運行之前onStartCommand()並返回START_STICKY

我越來越想知道爲什麼我AlarmReceiver創建一個服務,而不僅僅是直接顯示該通知。

同意。如果您計劃進行更多的工作,涉及磁盤或網絡I/O,則然後使用IntentService(後臺線程,服務自動停止)。否則,我只是把它放在onReceive()中,並稱它爲好。

+0

非常感謝。我在閱讀完你的回答後意識到,我完全錯誤地輸入了新的問題 - 它每天都沒有發射一次(這就是我想要的,就像你說的那樣),它只是一次發射完全停止。它不會再發生。但即便如此,我認爲放棄這項服務並將通知轉移到AlarmReceiver中仍然可以解決問題。 – andygeers

+0

@andygeers:另外請注意,在某些設備上,特別是某些SONY Xperia機型,可以禁用'_WAKEUP'報警(「STAMINA模式」)並將其轉換爲非'_WAKEUP'報警。請參閱http://commonsware.com/blog/2013/03/08/warning-xperia-z-stamina-alarmmanager.html和http://commonsware.com/blog/2013/03/11/more-xperia-alarmmanager .html – CommonsWare

+0

將通知直接放在alaemreceiver中似乎很好地訣竅 – andygeers

0

我只是想爲所有遇到AlarmManager和Android 4問題的人添加。4+,這是真正的重要您添加stopSelf();,像@CommonsWave已經說了,到內服務您的onStartCommand()的底部,這是從廣播接收器