2012-10-12 95 views
5

Objetivo: La notificación aparece todos los días, a las 2 PM, si se cumple determinada condición.Notificaciones repetitivas en Android 4

Ejemplo: Para simplificar, consideremos que la condición, comprobada con conexión a Internet, se cumple todos los días. Si hoy es después de las 2 p.m., comenzaremos las notificaciones a partir de mañana. Por ejemplo, el usuario inicia la aplicación a las 4 p.m. del lunes y recibe las notificaciones el martes a las 2 p.m., el miércoles a las 2 p.m., el jueves a las 2 p.m., etc.

Problema: A las 2 PM hay una primera notificación, pero luego recibo la misma notificación una y otra vez, al azar.

Parece que el problema es solo en Android> = 4.0. Funciona bien en Androids anteriores.

Así es como enviar una notificación:

public class NotifyService extends Service 
{  
static final int NOTIFICATION_ID = 1; 
// ... 

@Override 
public IBinder onBind(Intent intent) 
{ 
    return null; 
} 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) 
{ 
    try 
    { 
     Symbol biggest = getBiggestMover(); 
     if (biggest != null) 
     { 
      String title = getString(R.string.app_name); 
      String text = getNotificationText(biggest.symbol, biggest.change); 
      sendNotification(title, text); 
     } 
    } 
    catch (Exception e) 
    { 
     // If there is Internet problem we do nothing, don't want to disturb the user. 
     e.printStackTrace(); 
    } 

    return super.onStartCommand(intent, flags, startId); 
} 

/** @return Symbol which is the biggest mover today. If there is no big mover - null is returned. 
* @throws Exception If there is Internet problem. */ 
private Symbol getBiggestMover() throws Exception 
{ 
    Symbol biggest = null; 
    Symbol[] equities = Network.getTraded(SymbolType.EQUITY); 
    for (Symbol equity : equities) 
    { 
     if (Utilities.isToday(equity.lastTraded) && isBigMove(equity.change) && isBigger(equity, biggest)) 
     { 
      biggest = equity; 
     } 
    } 
    return biggest; 
} 

private void sendNotification(String title, String text) 
{ 
    Notification notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis()); 
    notification.flags = Notification.FLAG_AUTO_CANCEL; 

    Intent clickIntent = new Intent(this, MainActivity.class); 
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, clickIntent, PendingIntent.FLAG_CANCEL_CURRENT); 

    notification.setLatestEventInfo(this, title, text, pendingIntent); 

    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
    manager.notify(NOTIFICATION_ID, notification); 
} 
// ... 
} 

sendNotification() se llama a las 2 de la tarde, debido a la AlarmManager:

public class ServiceStarter extends BroadcastReceiver 
{ 

@Override 
public void onReceive(Context context, Intent intent) 
{ 
    setNotificationAlarm(context); 
} 

/** Set repeating notifications every 24 hours. */ 
public static void setNotificationAlarm(Context context) 
{ 
    Intent intent = new Intent(context, NotifyService.class); 
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 
    PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); 

    final int oneDay = 24 * 60 * 60 * 1000; 
    alarmManager.setRepeating(AlarmManager.RTC, getTriggerTime(), oneDay, pendingIntent); 
} 

private static long getTriggerTime() 
{ 
    GregorianCalendar calendar = new GregorianCalendar(); 
    calendar.set(GregorianCalendar.HOUR_OF_DAY, 14); 
    calendar.set(GregorianCalendar.MINUTE, 0); 
    calendar.set(GregorianCalendar.SECOND, 0); 
    calendar.set(GregorianCalendar.MILLISECOND, 0); 

    if (calendar.before(new GregorianCalendar())) 
    { 
     calendar.add(GregorianCalendar.DAY_OF_MONTH, 1); 
    } 

    return calendar.getTimeInMillis(); 
} 

} 

setNotificationAlarm() se llama desde 2 lugares. Primero, al inicio de la aplicación. En segundo lugar, desde el código anterior, cuando el teléfono se reinicia (onReceive() recibe BOOT_COMPLETED). Lo hago porque cuando el usuario apaga el teléfono, AlarmManager borra sus alarmas.

Así que todo debería funcionar, porque alarmManager.setRepeating() anula la alarma anterior.

He descubierto que alguien tenía el mismo problema, pero también la respuesta no:
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/t_tDU4PwR3g

También aquí me encontré con un problema similar: http://comments.gmane.org/gmane.comp.handhelds.android.devel/171471

Hace algún tiempo me preguntaron cómo crear este tipo de notificaciones , por lo que este se relaciona:
Everyday notifications at certain time

+1

En 'sendNotification', reemplace' getApplication() '' con this', reemplace 'getBaseContext()' 'con this', y reemplace' Intent.FLAG_ACTIVITY_NEW_TASK' con algo que pertenece allí, como 'Intent' las banderas no entran en métodos estáticos en 'PendingIntent'. Además, no use 'RTC_WAKEUP' con un' getService() '' PendingIntent', ya que no es confiable - use [my 'WakefulIntentService'] (https://github.com/commonsguy/cwac-wakeful) o alguna otra cosa eso funciona a partir de un 'getBroadcast()' 'PendingIntent'. – CommonsWare

+1

Más allá de eso, use 'adb shell dumpsys alarm' para examinar sus alarmas programadas, use los puntos de interrupción para ver qué desencadena su método' sendNotification() ', etc. – CommonsWare

+1

Muchas gracias @CommonsWare, seguí sus consejos. Sin embargo, el problema todavía ocurre en los teléfonos móviles con Android 4. ¿Es posible que exista algún error en su implementación de API? Debido a que he leído que en Android 4 introdujeron "notificaciones enriquecidas", por lo que han cambiado el código un poco. –

Respuesta

1

uso AlarmManager.RTC_WAKEUP INSTE d de AlarmManager.RTC

En AlarmManager.RTC

hora de alarma en System.currentTimeMillis() (tiempo de reloj de pared en UTC). Esta alarma no activa el dispositivo; si se apaga mientras el dispositivo está dormido, no se enviará hasta la próxima vez que el dispositivo se despierte.

donde como en AlarmManager.RTC_WAKEUP

hora de alarma en System.currentTimeMillis() (tiempo de reloj de pared en UTC), que despertará el dispositivo cuando sale.

+0

Esto está mal, de acuerdo con el primer comentario a mi publicación que fue hecho por @CommonsWare. "Además, no use RTC_WAKEUP con un GetService() PendingIntent, ya que no es confiable." –

1

Tenía el mismo problema en el dispositivo ICS +. Mi solución fue muy simple-> Ponga la hora actual en las preferencias compartidas cuando se muestra la notificación. Antes de eso siempre verifica si realmente se pasa el intervalo, y si no solo aborta.

  long lastnotification = sharedPrefs.getLong("lnnd", -1); 
      Calendar now = Calendar.getInstance(); 
      if (!namedayalarmEnabled) { 
        return; 
      } 
      if (lastnotification > 1) { 
        Calendar last = Calendar.getInstance(); 
        last.setTimeInMillis(lastnotification); 
        long distance = (now.getTimeInMillis() - last 
            .getTimeInMillis()); 
        if (distance < YOURINTERVAL) { 
          return; 
        } else { 
          SharedPreferences.Editor editor = sharedPrefs.edit(); 
          editor.putLong("lnnd", now.getTimeInMillis()); 
          editor.commit(); 
        } 
      } 
Cuestiones relacionadas