Точное время для пользовательских уведомлений в Android


Я разрабатываю приложение для Android для консультирования. Клиент может просмотреть свою запланированную встречу в приложении. Например,

Следующая встреча: 31 декабря 2016 года 10: 00 утра

Теперь мне нужно сделать так, чтобы пользователь получил 2 уведомления-напоминания о встрече. Один на 7 дней раньше, а другой на 3 дня раньше. Я сохраняю эту дату (31 декабря 2016 г. 10: 00) как String , чтобы извлечь год, месяц и т. д. Я обнаружил, что мне нужно написать какой-то сервис, который будет отправлять это уведомление. Это то, что я пытался (не завершено):

public class NotificationService extends Service {
    @Override
    public void onCreate() {
        Intent resultIntent=new Intent(this, MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);
        Notification nBuilder = new Notification.Builder(this)
                .setContentTitle("Don't miss! ")
                .setTicker("Notification!")
                .setContentIntent(pIntent)
                .setDefaults(Notification.DEFAULT_SOUND)
                .setAutoCancel(true)
                .setSmallIcon(R.drawable.my_logo)
                .setContentText("7 days left till your appointment...")
                //.setWhen(System.currentTimeMillis())
                .build();
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        nBuilder.flags |=Notification.FLAG_AUTO_CANCEL;
        notificationManager.notify(1,nBuilder);
    }

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

И метод, который я не знаю, откуда вызвать:

public void reminder() {
    Intent intent  = new Intent(getActivity(), MainActivity.class);

    AlarmManager manager =(AlarmManager) getActivity().getSystemService(Activity.ALARM_SERVICE);
    PendingIntent pendingIntent = PendingIntent.getService(getActivity().getApplicationContext(),
            0,intent, 0);
    Calendar cal=Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 8); 
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    manager.setRepeating(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(),24*60*60*1000,pendingIntent);
}

Для целей тестирования я установил час/минуту/секунду вручную, но, очевидно, мне нужно будет извлечь его из даты String.

1 2

1 ответ:

Сначала нужно написать IntentService. Вот пример, вы можете написать код для отображения уведомления в функции processNotification.

public class NotificationIntentService extends IntentService {

    private static final String ACTION_START = "ACTION_START";

    public NotificationIntentService() {
        super(NotificationIntentService.class.getSimpleName());
    }

    public static Intent createIntentStartNotificationService(Context context) {
        Intent intent = new Intent(context, NotificationIntentService.class);
        intent.setAction(ACTION_START);
        return intent;
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            String action = intent.getAction();
            if (ACTION_START.equals(action))
                processNotification();

        } finally {
            WakefulBroadcastReceiver.completeWakefulIntent(intent);
        }
    }

    private void processNotification() {
        Intent resultIntent=new Intent(this, MainActivity.class);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);
        Notification nBuilder = new Notification.Builder(this)
                .setContentTitle("Don't miss! ")
                .setTicker("Notification!")
                .setContentIntent(pIntent)
                .setDefaults(Notification.DEFAULT_SOUND)
                .setAutoCancel(true)
                .setSmallIcon(R.drawable.my_logo)
                .setContentText("7 days left till your appointment...")
                .build();
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        nBuilder.flags |=Notification.FLAG_AUTO_CANCEL;
        notificationManager.notify(1, nBuilder);
    }
}

И затем создать NotificationEventReceiver

public class NotificationEventReceiver extends WakefulBroadcastReceiver {

    private static final String ACTION_START_NOTIFICATION_SERVICE = "ACTION_START_NOTIFICATION_SERVICE";

    public static void setupAlarm(Context context, long interval) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent alarmIntent = getStartPendingIntent(context);

        alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), interval, alarmIntent);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Intent serviceIntent = null;
        if (ACTION_START_NOTIFICATION_SERVICE.equals(action)) {
            serviceIntent = NotificationIntentService.createIntentStartNotificationService(context);
        }

        if (serviceIntent != null) {
            startWakefulService(context, serviceIntent);
        }
    }

    private static PendingIntent getStartPendingIntent(Context context) {
        Intent intent = new Intent(context, NotificationEventReceiver.class);
        intent.setAction(ACTION_START_NOTIFICATION_SERVICE);
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }
}

И NotificationServiceStarterReceiver

public final class NotificationServiceStarterReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        long interval = getIntent().getLongExtra("alarm_interval", 0);
        NotificationEventReceiver.setupAlarm(context, interval);
    }
}

Добавьте их в свой AndroidManifest.xml внутренний <application> тег

<service
    android:name="YourPackage.NotificationIntentService"
    android:enabled="true"
    android:exported="false" />

<receiver android:name="YourPackage.BroadcastReceiver.NotificationEventReceiver" />
<receiver android:name="YourPackage.BroadcastReceiver.NotificationServiceStarterReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.TIMEZONE_CHANGED" />
        <action android:name="android.intent.action.TIME_SET" />
    </intent-filter>
</receiver>
Теперь из вашего Activity Вы можете вызвать функцию setupAlarm() inside onCreate.
NotificationEventReceiver.setupAlarm(getApplicationContext(), interval);

Вам нужно добавить разрешение WAKE_LOCK в манифест.

<uses-permission android:name="android.permission.WAKE_LOCK" />

Здесь вы видите, что можете передать interval следующее уведомление будет показано. Используйте interval с умом. Вы можете сохранить текущие статусы встречи в базе данных, а затем при необходимости вызвать сигнал тревоги, передав соответствующий интервал следующего сигнала тревоги. Вот в чем идея.

Обновить

Поэтому в вашем случае вы не хотите показывать уведомление, когда пользователь выходит из системы. Поэтому в этом случае вы можете рассмотреть возможность сохранения SharedPreference для сохранения статуса входа. Вы можете вызвать функцию processNotification на основе значения на хранении.

Таким образом, псевдокод может выглядеть следующим образом.
if(pref.getBoolean("login_status", false)) {
    // If the login status is true, process the notification
    processNotification();
} else {
    // Do nothing
}