Alarmmanager как сделать несколько уведомлений
Перейти к содержимому

Alarmmanager как сделать несколько уведомлений

  • автор:

Использование AlarmManager+Notifications

Народ, подскажите, пожалуйста, как правильно выводить уведомления (именно нотификейшены — не тосты) при выключенном приложении в заданное время?
Я уже кучу примеров нашел и в Инете, и здесь на форуме, но везде написано по-разному, а что еще хуже, так это то, что я не могу понять как все это работает, а следом за мной не работает и ни один из примеров.
У меня есть MainActivity.class. Пожалуйста, подскажите, что нужно прописать в нем, какие классы еще нужно создать, и что писать в них. Люди добрые, я буду чисто по-человечески признателен, если кто-то найдет время выложить здесь код подобной работающей программы с комментами, чтобы было понятно как все это работает.

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

push notifications
Добрый день! Занимаюсь push notifications уведомлениями. Аккаунт девелопера купил, имею свой.

Не работает Notifications
Есть кнопка по клику должно быть уведомление, но оно не показывается. .

Firebase Notifications
Добрый день. Уважаемые пользватели есть несколько идиотский вопрос, не могли бы вы тыкнуть меня.

Отсутствует flash.notifications
Пишу в Adobe Flash Builder 4.6 сетевое приложение под ios. Есть необходимость использовать push.

3378 / 2150 / 352
Регистрация: 13.01.2012
Сообщений: 8,352

Elkatib, «брехня». почему бы не открыть какой-нибудь стартандроид и не повыдергивать куски кода из разделов сервисы и алармы наложив на это сверху щепотку кода с какого-нибудь стека учитывающую особенности алармов на последних андроидах в dozemode ?

1569 / 1167 / 426
Регистрация: 08.05.2012
Сообщений: 5,219

Есть гайд на офф сайте, даже на русском:
https://developer.android.com/. html?hl=ru
Раз уж везде «по-разному», то бери инфу с первоисточника.

Регистрация: 08.01.2016
Сообщений: 314

ExFau$t, В статье сказано про Уведомления (нотификации). С этим я более или менее разобрался. А вот как их объединить в работающий код? Проблемы в основном с AlarmManager.

1569 / 1167 / 426
Регистрация: 08.05.2012
Сообщений: 5,219

ЦитатаСообщение от Elkatib Посмотреть сообщение

как их объединить
Скопировать и вставить, аналогично с AlarmManager.

ЦитатаСообщение от Elkatib Посмотреть сообщение

Проблемы в основном с AlarmManager.
Выкладываешь код, говоришь в чём проблема, получаешь ответ.
Регистрация: 08.01.2016
Сообщений: 314

ExFau$t, В общем, поехал купил книгу «Андроид Программирование для профессионалов» Б. Харди. К сожалению для чайников книг не было.))))
Этот код я переписал с их примера, который запихнул в новый класс «MyAlarm»:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
package com.zoro.zoro; import android.app.AlarmManager; import android.app.IntentService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.SystemClock; public abstract class MyAlarm extends IntentService { private static final String TAG = "MyAlarm"; private static final int POLL_INTERVAL = 1000 * 60; public MyAlarm(String name) { super(name); } public static Intent newIntent(Context context) { return new Intent (context, MyAlarm.class); } public static void setServiceAlarm(Context context, boolean isOn){ Intent i = MyAlarm.newIntent(context); PendingIntent pi = PendingIntent.getService(context, 0, i, 0); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); if (isOn) { alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), POLL_INTERVAL, pi); }else{ alarmManager.cancel(pi); pi.cancel(); } } }

Как понимаю, этот код должен запускать процесс, который будет работать даже при выключенной программе.
1) Где тут вообще код нотификаций, которые будут показывать уведомления непосредственно?
2) Как сделать, чтобы код включался не каждые 60 секунд, как пишут в книге, а в 20:00 каждого дня?
3) Как вообще запустить АлармМенеджер. В книгу пишут запихнуть этот код в MainActivity:

MyAlarm.setServiceAlarm(getActivity(), true);

но Студия подчеркивает красным это место getActivity(). Вообщем я даже этот пример не смог запустить.

Урок 119. PendingIntent – флаги, requestCode. AlarmManager

Перед тем, как продолжить тему виджетов, нам надо будет знать две темы: PendingIntent и AlarmManager.

С PendingIntent мы уже мельком встречались при работе с уведомлениями (Notifications) в Уроке 99. Вспомним, как создается этот объект. Мы создаем обычный Intent с нужными нам параметрами. Затем мы создаем PendingIntent каким-либо из методов: getActivity, getBroadcast, getService. Здесь имя метода определяет, какой тип объекта будет вызван с помощью нашего Intent. Ведь мы сами, когда отправляем Intent, явно говорим системе, что хотим вызвать: startActivity, sendBroadcast, startService.

Методы создания PendingIntent одинаковы по параметрам и требуют на вход:

context – тут все понятно.
requestCode – в хелпе почему-то написано «currently not used». Но при этом использовать их вполне можно. Это своего рода ключи, чтобы отличать один PendingIntent от других при необходимости.
intent – этот Intent будет впоследствии использован для вызова activity/broadcast/service (в зависимости от метода создания)
flags – флаги, влияющие на поведение и создание PendingIntent

Создавая и передавая другому приложению PendingIntent (с Intent внутри), мы предоставляем ему возможность и полномочия отправлять Intent от нашего имени. В этом уроке мы будем работать с PendingIntent. Увидим, что при создании есть свои нюансы, и разберемся, как можно использовать флаги и requestCode.

Вторая тема урока – AlarmManager. Это планировщик, которому можно передать PendingIntent и сказать, когда именно надо будет его использовать. В общем, что-то типа будильника. Там особо не о чем говорить, поэтому рассмотрим его совсем кратко.

PendingIntent

Создадим пример, в котором будем создавать различные PendingIntent и использовать их в Notifications. Результатом выполнения будет вызов BroadcastReceiver, в котором будем логировать входящую информацию.

Project name: P1191_PendingIntent
Build Target: Android 2.3.3
Application name: PendingIntent
Package name: ru.startandroid.develop.p1191pendingintent
Create Activity: MainActivity

Добавим строки в strings.xml:

Button1 Button2

Создаем Receiver.java:

package ru.startandroid.develop.p1191pendingintent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class Receiver extends BroadcastReceiver < final String LOG_TAG = "myLogs"; @Override public void onReceive(Context ctx, Intent intent) < Log.d(LOG_TAG, "onReceive"); Log.d(LOG_TAG, "action = " + intent.getAction()); Log.d(LOG_TAG, "extra = " + intent.getStringExtra("extra")); >>

Это наш Receiver, в который будут падать Intent из PendingIntent. В нем мы читаем Intent и выводим в лог action и один параметр из extra-данных. Не забудьте прописать этот класс в манифесте.

Layout-файл main.xml:

Только две кнопки.

MainActivity.java:

package ru.startandroid.develop.p1191pendingintent; import android.app.Activity; import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; public class MainActivity extends Activity < final String LOG_TAG = "myLogs"; NotificationManager nm; AlarmManager am; Intent intent1; Intent intent2; PendingIntent pIntent1; PendingIntent pIntent2; protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.main); nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); am = (AlarmManager) getSystemService(ALARM_SERVICE); >public void onClick1(View view) < intent1 = createIntent("action 1", "extra 1"); pIntent1 = PendingIntent.getBroadcast(this, 0, intent1, 0); intent2 = createIntent("action 2", "extra 2"); pIntent2 = PendingIntent.getBroadcast(this, 0, intent2, 0); compare(); >public void onClick2(View view) < >Intent createIntent(String action, String extra) < Intent intent = new Intent(this, Receiver.class); intent.setAction(action); intent.putExtra("extra", extra); return intent; >void compare() < Log.d(LOG_TAG, "intent1 = intent2: " + intent1.filterEquals(intent2)); Log.d(LOG_TAG, "pIntent1 = pIntent2: " + pIntent1.equals(pIntent2)); >void sendNotif(int id, PendingIntent pIntent) < Notification notif = new Notification(R.drawable.ic_launcher, "Notif " + id, System.currentTimeMillis()); notif.flags |= Notification.FLAG_AUTO_CANCEL; notif.setLatestEventInfo(this, "Title " + id, "Content " + id, pIntent); nm.notify(id, notif); >>

Метод createIntent создает Intent с указанными параметрами.

Метод sendNotif создает уведомление с указанными ID и PendingIntent.

Метод compare выводит в лог результат сравнения Intent и PendingIntent. Для Intent используем метод filterEquals, который сравнивает Intent по action, data и пр., игнорируя extra-данные .

В onClick1 мы, используя все эти методы, будем создавать различные комбинации, и смотреть, что получается. Сейчас мы там создаем пару Intent и PendingIntent и просто сравниваем их, нигде не используя. В качестве флагов и requestCode мы пока используем нули.

В onClick2 пока ничего не пишем.

Все сохраним и запустим приложение.

Жмем Button1, смотрим лог.

intent1 = intent2: false
pIntent1 = pIntent2: false

Видим, что Intent-ы не равны (т.к. у них различается параметр action). А PendingIntent не равны потому, что их Intent не равны между собой.

Давайте теперь сравняем основные части Intent. Перепишем onClick1:

public void onClick1(View view)

action будут равны, а Extra отличается. Сохраним, запустим. Жмем Button1:

intent1 = intent2: true
pIntent1 = pIntent2: true

Теперь метод filterEquals говорит нам, что Intent равны. Напомню – это потому, что этот метод не учитывает данные в Extra. PendingIntent получились равны, потому что (по версии filterEquals) равны их Intent. Этот момент надо четко понять, т.к. он очень сильно влияет на создание новых PendingIntent.

Попробую расписать алгоритм, как я его понимаю. Когда приложение создает PendingIntent, система его хранит в себе. При этом, Intent создаваемого PendingIntent сравнивается с Intent уже существующих PendingIntent. Если есть PendingIntent с Intent равным Intent создаваемого PendingIntent, то создаваемый PendingIntent получит этот существующий Intent. А Intent, с которым мы его пытались создать будет отброшен.

Т.е. в нашем случае мы создали pIntent1 с intent1, система его хранит. Далее мы создаем pIntent2 с intent2. Система проверяет существующие PendingIntent, и видит, что есть pIntent1 с intent1, и этот intent1 равен intent2. И ваш созданный pIntent2, теперь содержит intent1. А intent2 выкинут. pIntent1 при этом, разумеется, также остается со своим intent1. Просто теперь один Intent будет использоваться двумя PendingIntent-ами.

Можно сказать, что дефолтное поведение дает нам полную копию существующего PendingIntent, вместо создаваемого, если их Intent-ы равны без учета extra-данных.

Давайте убедимся в этом. Перепишем onClick1:

public void onClick1(View view)

Будем создавать разные Intent, использовать их в PendingIntent и отправлять уведомления.

Все сохраним и запустим. Жмем Button1. Появились два уведомления.

Жмем первое (Title 1), смотрим лог:

onReceive
action = action 1
extra = extra 1

Все верно. Что помещали в intent1, то и получили в результате срабатывания pIntent1.

Жмем второе (Title 2) уведомление:

onReceive
action = action 2
extra = extra 2

Также все верно. Что помещали в intent2, то и получили в результате срабатывания pIntent2.

Теперь сделаем action одинаковым

public void onClick1(View view)

Сохраняем, запускаем. Жмем Button1. Жмем первое уведомление:

onReceive
action = action
extra = extra 1

Жмем второе уведомление и наблюдаем в логах разрыв шаблона такое:

onReceive
action = action
extra = extra 1

При втором уведомлении сработал pIntent2, в который мы помещали intent2 c другим extra. Но получили мы extra из intent1. Причины описаны выше. Система увидела, что intent1 равен intent2 (без учета данных в Extra) и созданному pIntent2 дала intent1.

Это дефолтное поведение системы, но, к счастью, мы можем на него повлиять. Для этого и нужны флаги и requestCode, которые передаются в метод создания PendingIntent.

Флаги

Определимся с формулировкой. Фраза «создаваемый PendingIntent похож на существующий» означает, что равны (без extra) Intent-ы двух этих PendingIntent.

FLAG_CANCEL_CURRENT

Если система видит, что создаваемый с таким флагом PendingIntent похож на существующий, то она отменит (удалит) существующий.

public void onClick1(View view)

Сохраняем, запускаем, жмем Button1, жмем первое уведомление. В логах ничего. pIntent1 был отменен системой в момент создания pIntent2, т.к. они похожи, а pIntent2 содержал флаг FLAG_CANCEL_CURRENT. И т.к. первое уведомление было создано с использованием pIntent1, оно ничего и не сделало.

Жмем второе уведомление.

onReceive
action = action
extra = extra 2

pIntent2 отменил pIntent1, но сам остался и выполнился.

FLAG_UPDATE_CURRENT

Этот флаг включает поведение, обратное дефолтному. Если система видит, что создаваемый с таким флагом PendingIntent похож на существующий, то она возьмет extra-данные Intent создаваемого PendingIntent и запишет их вместо extra-данных Intent существующего PendingIntent. Проще говоря, существующий PendingIntent будет использовать Intent из создаваемого.

public void onClick1(View view)

Сохраняем, запускаем, жмем Button1, жмем первое уведомление. В логах:

onReceive
action = action
extra = extra 2

Видим, что pIntent1 использовал intent2 вместо intent1. Жмем второе уведомление :

onReceive
action = action
extra = extra 2

Данные из intent2. Получилось, что в обоих PendingIntent использовался intent2.

FLAG_ONE_SHOT

PendingIntent с этим флагом сработает лишь один раз. Сначала сделаем пример без флага. Перепишем onClick1:

public void onClick1(View view)

Будем использовать один PendingIntent в обоих уведомлениях.

Сохраняем, запускаем, жмем Button1, жмем первое уведомление. В логах:

onReceive
action = action
extra = extra 1

жмем второе уведомление:

onReceive
action = action
extra = extra 1

Все логично. Оба уведомления использовали один pIntent1 с intent1.

Теперь используем флаг:

public void onClick1(View view)

Этот флаг отменит PendingIntent после первого применения.

Сохраняем, запускаем, жмем Button1, жмем первое уведомление. В логах:

onReceive
action = action
extra = extra 1

Все ок, pIntent1 сработал. Жмем второе уведомление – в логах ничего. pIntent1 не сработал. Система увидела FLAG_ONE_SHOT и отменила PendingIntent после первого вызова. Т.е. PendingIntent с таким флагом может быть использован только один раз.

FLAG_NO_CREATE

PendingIntent не будет создан, если среди существующих нет похожего.

Перепишем onClick1 и onClick2

public void onClick1(View view) < intent1 = createIntent("action", "extra 1"); pIntent1 = PendingIntent.getBroadcast(this, 0, intent1, 0); Log.d(LOG_TAG, "pIntent1 created"); >public void onClick2(View view)

Сохраняем, запускаем. Жмем Button2, в логах:

pIntent2 is null

pIntent2 не создался, т.к. не было создано похожих PendingIntent. Дальнейшие нажатия будут возвращать тот же результат.

Теперь нажмем Button1, а затем Button2:

pIntent1 created
pIntent2 created

После создания pIntent1, получилось создать и pIntent2 (т.к. похожий pIntent1 существовал). Зачем нужен такой флаг? Единственное, что мне приходит в голову – с его помощью можно проверить существование в системе определенного PendingIntent. Если такой PendingIntent существует, то он вам и вернется (здесь действует дефолтное правило), а если не существует – то получим null.

Как оно там внутри работает

Наверняка назрели вопросы типа: где в системе хранятся эти PendingIntent, как долго они хранятся и когда отменяются (удаляются)?

К сожалению, не знаю. Самому было бы интересно узнать.

В последнем примере:

Если создать pIntent1, закрыть Activity, открыть Activity и создать pIntent2, то он создастся.
Если создать pIntent1, убить процесс, открыть Activity и создать pIntent2, то он создастся.
Если создать pIntent1, переустановить приложение, открыть Activity и создать pIntent2, то он не создастся.

Т.е. переустановка приложения точно скидывает все созданные в нем PendingIntent.

Если есть какие-нить мысли или ссылки на этот счет, пишите на форуме.

Отмена

Вы всегда можете вручную отменить любой PendingIntent методом cancel.

public void onClick1(View view) < intent1 = createIntent("action", "extra 1"); pIntent1 = PendingIntent.getBroadcast(this, 0, intent1, 0); sendNotif(1, pIntent1); >public void onClick2(View view)

Все сохраним, запустим, жмем Button1. Появилось уведомление. Теперь жмем Button2. pIntent1 отменился. Но при этом, заметьте, уведомление спокойно продолжает себе висеть. Ему неважно, живой его PendingIntent или нет.

Нажимаем на уведомление и видим, что в логах ничего не происходит, т.к. PendingIntent был отменен.

requestCode

Что делать, если у нас есть Intent-ы, различающиеся только extra-данными, и нам все-таки нужно получить разные PendingIntent с ними? Можно использовать requestCode. При их использовании PendingIntent не будут считаться похожими, даже при равных Intent.

Перепишем onClick1:

public void onClick1(View view)

Используем requestCode = 1 для pIntent1 и 2 для pInten2.

Сохраняем, запускаем, жмем Button1. В логах:

intent1 = intent2: true
pIntent1 = pIntent2: false

Intent-ы равны, а PendingIntent-ы (благодаря requestCode) – нет.

Жмем первое уведомление

onReceive
action = action
extra = extra 1

Жмем второе уведомление

onReceive
action = action
extra = extra 2

Все сработало, как и ожидалось. Никто ни у кого Intent-ы не менял. Все остались при своих.

Есть еще вариант как сделать разные PendingIntent. Он подходит, если у вас в Intent не используется поле data. Туда можно поместить какие-то свои бессмысленные Uri, содержащие ID, которые просто будут разными, чтобы Intent-ы, а следовательно и PendingIntent-ы получились разными.

Либо можно, чтобы весь Intent преобразовывался в Uri и помещался в data. Делается это так:

public void onClick1(View view)

Метод toUri преобразует Intent со всем его содержимым и всеми параметрами в строку. parse преобразует строку в Uri. Теперь даже если основные параметры Intent-ов будут одинаковы, то разное содержимое extra-данных сделает полученные Uri разными. И Intent-ы будут отличаться по полю data.

AlarmManager

Разобрались с PendingIntent. Взглянем на AlarmManager. Как я уже написал, да и как понятно из названия объекта, он отвечает за то, чтобы срабатывать по расписанию. «Срабатывать» означает использовать ваш PendingIntent, который вы ему отправите.

Два основных метода: set и setRepeating. Они позволяют запланировать, соответственно, разовое и повторяющееся событие.

Рассмотрим пример. Перепишем методы:

public void onClick1(View view) < intent1 = createIntent("action 1", "extra 1"); pIntent1 = PendingIntent.getBroadcast(this, 0, intent1, 0); intent2 = createIntent("action 2", "extra 2"); pIntent2 = PendingIntent.getBroadcast(this, 0, intent2, 0); Log.d(LOG_TAG, "start"); am.set(AlarmManager.RTC, System.currentTimeMillis() + 4000, pIntent1); am.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 3000, 5000, pIntent2); >public void onClick2(View view)

В onClick1 создадим два разных PendingIntent. Первый отправим методом set. На вход метод требует тип «будильника», время срабатывания (в милисекундах) и PendingIntent.

Типы будильника бывают следующие: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC и RTC_WAKEUP. В чем отличие между ними?

Те, название которых начинается с RTC, ориентируются на системное время. И время запуска таких будильников надо указывать относительно System.currentTimeMillis. Т.е. это RTC и RTC_WAKEUP.

Те, название которых начинается с ELAPSED_REALTIME, ориентируются на время от начала загрузки оси (включения устройства). Время запуска таких будильников надо указывать относительно SystemClock.elapsedRealtime(). Т.е. это ELAPSED_REALTIME и ELAPSED_REALTIME_WAKEUP.

Те, в названии которых есть WAKEUP, при срабатывании будут выводить устройство из спячки. Т.е. это ELAPSED_REALTIME_WAKEUP и RTC_WAKEUP.

Тут надо не путать спячку с выключенным экраном. Экран может быть выключен, но устройство вовсю будет работать. А когда задач нет устройство уходит в спячку, вырубая процессор для экономии энергии. Если будильники с типом не WAKEUP должны сработать, а устройство в это время спит, то их запуск откладывается до пробуждения. А WAKEUP-будильники разбудят устройство.

Вернемся к методу set. Используем здесь тип RTC, а, значит, время запуска (второй параметр метода) указываем относительно системного времени. Укажем текущее время + 4 секунды. Т.е. будильник сработает через 4 секунды после текущего времени создания. А когда он сработает, он выполнит pIntent1 (третий параметр метода).

Второй будильник ставим методом setRepeating. Он похож на set, только позволяет задать еще период повтора срабатывания. Для примера используем здесь тип ELAPSED_REALTIME. С таким типом время запуска мы должны указать, через сколько милисекунд после старта системы сработает будильник. Мы берем время уже прошедшее со старта (SystemClock.elapsedRealtime()), тем самым получая текущее время, и прибавляем к нему 3 секунды. Период повтора (третий параметр метода) сделаем равным 5 секунд. При срабатывании будет выполнен pIntent2.

Т.е. после того, как мы нажмем кнопку у нас установятся два будильника.

Первый – однократный, через 4 секунды от текущего времени, pIntent1.

Второй – повторяющийся каждые 5 сек., с первым запуском через 3 секунды от текущего времени.

В onClick2 мы будем выключать второй будильник, чтобы он у нас не работал вечно. Для этого выполняем метод cancel с указанием PendingIntent, который используется в будильнике.

Все сохраняем, запускаем приложение. Жмем Button1. В логах наблюдаем, как начали срабатывать будильники. Секунд через 20 жмем кнопку Button2, движуха в логах прекратилась. Смотрим логи:

07:55:22.380: start
07:55:25.450: onReceive
07:55:25.450: action = action 2
07:55:25.459: extra = extra 2
07:55:26.430: onReceive
07:55:26.430: action = action 1
07:55:26.430: extra = extra 1
07:55:30.499: onReceive
07:55:30.499: action = action 2
07:55:30.499: extra = extra 2
07:55:35.429: onReceive
07:55:35.429: action = action 2
07:55:35.429: extra = extra 2
07:55:40.450: onReceive
07:55:40.450: action = action 2
07:55:40.450: extra = extra 2

Второй будильник сработал через 3 секунды после старта и далее срабатывал каждые 5 сек, пока мы его не выключили методом cancel. А первый сработал один раз, через 4 секунды. Все, как и задумывалось.

Есть еще метод setInexactRepeating. Он аналогичен методу setRepeating, но периодичность его срабатывания не всегда точно такая, какую вы указали. Он может подстраивать запуск вашего будильника под будильники, которые будут выполнены примерно в то же время. Сделано это для экономии энергии, чтобы не будить два раза устройство, если оно спит. Судя по хелпу погрешность запуска может быть значительной, так что используйте аккуратнее.

Расскажу еще несколько полезных фактов из жизни будильников.

Если вы запланируете будильник с просроченным временем запуска – он выполнится сразу же.

После перезагрузки устройства все будильники стираются.

Если вы попытаетесь создать два разных будильника на основе одного или похожих PendingIntent, то сработает только второй, а первый будет удален при создании второго.

public void onClick1(View view)

Создаем похожие PendingIntent и запланируем их в два разных будильника – через 2 и 4 секунды.

Сохраняем, запускаем. Жмем Button1. В логах видим:

8:03:59.669: start

8:04:03.740: onReceive

8:04:03.740: action = action

8:04:03.750: extra = extra 1

Видим, что пришел Intent из pIntent1, который мы использовали для первого будильника, но пришел он через 4 секунды. Что произошло? Выше мы уже рассмотрели, что произойдет при создании похожих PendingIntent — второй будет использовать Intent первого. Кроме того AlarmManager определил, что pIntent1 (используемый в первом будильнике) и pIntent2 (используемый во втором) похожи, и решил, что негоже иметь разные будильники, с одинаковыми PendingIntent. И оставил нам только последний созданный будильник, т.е. второй.

Как решить проблему одинаковости PendingIntent, мы уже рассмотрели выше. Повторяться не буду.

Тема вроде несложная для понимания, но достаточно сложная для объяснения. Все аспекты и варианты рассмотреть в одном уроке трудновато, поэтому если у вас остались какие-либо вопросы, то самым лучшим способом получить ответы на них будут тесты.

На следующем уроке:

— обрабатываем нажатия на виджет

Присоединяйтесь к нам в Telegram:

— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance

— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

Как отправлять уведомления по заданному времени?

Передо мной стоит задача отправки уведомлений по заданному времени пользователем. Например пользователь может создать несколько задач на определенное время, а приложение при наступлении этого времени шлет уведомление. Все действия выполняются строго в приложении без использования Firebase Cloud Messages

Я создал BroadcastReceiver с фильтром BOOT_COMPLETED, в котором запускается Service. В самом Service я создал логику пробежки по базе, определения времени и если время достигнуто, то выводит уведомление

В целом я понимаю как должно быть, но ничего не выходит, поэтому прошу вас разобраться с моими вопросам:
1. Как сделать так, чтобы приложение работало в фоне и выдавало уведомление даже через продолжительное время, даже когда приложение не запущено?
2. Где надо регистрировать BroadcastReceiver?
3. У меня при запуске intent в BroadcastReceiver при работе в фоне выдает ошибку: Not allowed to start service Intent
4. У меня при работе в приложении и выполнения BroadcastReceiver приложение перезапускает активити
5. Согласно статье, разрешение указанное я не смог найти android.permission.SCHEDULE_EXACT_ALARM
6. У меня в AlarmManager нет canScheduleExactAlarms(), хотя указано что метод есть

public void onReceive( Context context, Intent intent )
PendingIntent pendingIntent = PendingIntent.getBroadcast( this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT ); AlarmManager alarmManager = ( AlarmManager ) getSystemService( Context.ALARM_SERVICE ); if (pendingIntent != null && alarmManager != null ) alarmManager.cancel( pendingIntent ); alarmManager.setRepeating( alarmType, time, replace, pendingIntent );
  • Вопрос задан более двух лет назад
  • 139 просмотров

Создание уведомлений в Android на указанную дату и время

В моем приложении нужно реализовать чтобы при добавлении растения в локальную базу данных, пользователю через 2 дня прислало что нужно его полить. Подскажите пожалуйста как можно создать планирование уведомления через два дня после добавления. Также возможно ли создать много разных уведомлений, так как растение могут добавить не одно. Буду рад любой помощи, возможно есть специальная библиотека.

Отслеживать

задан 10 июн 2020 в 13:32

Pavlo Pavlov Pavlo Pavlov

49 5 5 бронзовых знаков

Возможный дубликат вопроса: Как отобразить уведомление единожды в день в строго определённое время?

10 июн 2020 в 14:08

Обратите внимание на Alarm Service developer.android.com/training/scheduling/alarms

10 июн 2020 в 14:09

@ВасяВоронцов Спасибо это помогло, если немножко разобраться и переделать всё работает, однако как я после после перезапуска телефона это уведомление не сработает?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *