【发布时间】:2015-12-29 19:13:17
【问题描述】:
我想在特定时间向我的应用发出通知。说每天早上 7 点我必须通知,即使应用程序已关闭。
我该怎么做?有教程吗? 请注明链接。
【问题讨论】:
标签: android android-notifications
我想在特定时间向我的应用发出通知。说每天早上 7 点我必须通知,即使应用程序已关闭。
我该怎么做?有教程吗? 请注明链接。
【问题讨论】:
标签: android android-notifications
首先您需要使用广播接收器。并且因为广播接收器只启动了很短的时间
来自 android 开发者博客。处理广播时,应用程序有固定的时间(当前为 10 秒)来完成其工作。如果在这段时间内没有完成,则认为应用程序行为不端,它的进程会立即进入后台状态,以便在需要时将其杀死以获取内存。
在此处使用意图服务是一种更好的做法,您有一个示例。
这是广播接收器类。
public class MyReceiver extends BroadcastReceiver {
public MyReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, MyNewIntentService.class);
context.startService(intent1);
}
}
并在清单中注册。
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="false" >
</receiver>
这是意图服务类。
public class MyNewIntentService extends IntentService {
private static final int NOTIFICATION_ID = 3;
public MyNewIntentService() {
super("MyNewIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Notification.Builder builder = new Notification.Builder(this);
builder.setContentTitle("My Title");
builder.setContentText("This is the Body");
builder.setSmallIcon(R.drawable.whatever);
Intent notifyIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 2, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//to be able to launch your activity from the notification
builder.setContentIntent(pendingIntent);
Notification notificationCompat = builder.build();
NotificationManagerCompat managerCompat = NotificationManagerCompat.from(this);
managerCompat.notify(NOTIFICATION_ID, notificationCompat);
}
}
并在清单中注册。
<service
android:name=".MyNewIntentService"
android:exported="false" >
</service>
然后在您的活动中设置警报管理器以在特定时间启动广播接收器并使用 AlarmManager setRepeating 方法重复它下面的示例将每天重复它。
Intent notifyIntent = new Intent(this,MyReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast
(context, NOTIFICATION_REMINDER_NIGHT, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
1000 * 60 * 60 * 24, pendingIntent);
希望对你有帮助。
【讨论】:
您可以使用AlarmManager在指定时间设置闹钟
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (!prefs.getBoolean("firstTime", false)) {
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 7);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 1);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("firstTime", true);
editor.apply();
}
我使用SharedPreferences 来检查这不是第一次运行应用程序,如果是,则设置警报,否则什么都不做,而不是在每次启动应用程序时重置警报。
警报发生时使用BroadcastReceiver 进行监听
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// show toast
Toast.makeText(context, "Alarm running", Toast.LENGTH_SHORT).show();
}
}
使用另一个接收器来收听设备启动,以便您可以重置警报
public class DeviceBootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
// on device boot compelete, reset the alarm
Intent alarmIntent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 7);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 1);
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
}
将权限添加到清单
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
然后注册你的接收器
<receiver android:name=".DeviceBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReceiver" />
【讨论】:
onCreate()方法中添加通知代码。
SharedPReference 第二天将如何工作?因为布尔值会是假的
SharedPreferences 应该只在应用程序第一次启动设置警报的情况下工作一次,然后它将布尔值设置为 true,即应用程序之前启动,以避免一遍又一遍地重置警报。
Serializable 对象未包装在 Bundle: see this answer 中,它们可能会为 null。
由于后台服务限制 (https://developer.android.com/about/versions/oreo/background.html#services),来自已接受答案的解决方案将无法在 Android 8 Oreo(api 级别 26)及更高版本上正常运行,并且当应用在后台:
java.lang.IllegalStateException: Not allowed to start service Intent xxx: app is in background
一种可能的解决方法是使用JobIntentService:
从JobIntentService 扩展您的Service 而不是IntentService 并使用onHandleWork 方法而不是onHandleIntent。
在AndroidManifest.xml 中将android:permission="android.permission.BIND_JOB_SERVICE" 添加到您的Service。
【讨论】:
BroadCastReceiver。我该如何解决?
这是我的解决方案,在 android 10 上进行了测试。还兼容所有以前版本的android。
MainActivity.class
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
....
reminderNotification();
}
public void reminderNotification()
{
NotificationUtils _notificationUtils = new NotificationUtils(this);
long _currentTime = System.currentTimeMillis();
long tenSeconds = 1000 * 10;
long _triggerReminder = _currentTime + tenSeconds; //triggers a reminder after 10 seconds.
_notificationUtils.setReminder(_triggerReminder);
}
NotificationUtils.class
public class NotificationUtils extends ContextWrapper
{
private NotificationManager _notificationManager;
private Context _context;
public NotificationUtils(Context base)
{
super(base);
_context = base;
createChannel();
}
public NotificationCompat.Builder setNotification(String title, String body)
{
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.noti_icon)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
}
private void createChannel()
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, TIMELINE_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
getManager().createNotificationChannel(channel);
}
}
public NotificationManager getManager()
{
if(_notificationManager == null)
{
_notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
}
return _notificationManager;
}
public void setReminder(long timeInMillis)
{
Intent _intent = new Intent(_context, ReminderBroadcast.class);
PendingIntent _pendingIntent = PendingIntent.getBroadcast(_context, 0, _intent, 0);
AlarmManager _alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
_alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, _pendingIntent);
}
}
ReminderBroadcast.class
public class ReminderBroadcast extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
NotificationUtils _notificationUtils = new NotificationUtils(context);
NotificationCompat.Builder _builder = _notificationUtils.setNotification("Testing", "Testing notification system");
_notificationUtils.getManager().notify(101, _builder.build());
}
}
AndroidManifest.xml
<application>
...
<receiver android:name=".custom.ReminderBroadcast"/>
</application>
注意:CHANNEL_ID 和 TIMELINE_CHANNEL_NAME,已在另一个类上创建。
例如,
CHANNEL_ID = "notification channel";
TIMELINE_CHANNEL_NAME = "Timeline notification";
对我的代码和错误有任何误解,请随时发表评论。我会尽快回复。
【讨论】:
相同的示例代码:
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmIntent = new Intent(context of current file, AlarmReceiver1.class);
AlarmReceiver1 = broadcast receiver
pendingIntent = PendingIntent.getBroadcast( Menu.this, 0, alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
alarmIntent.setData((Uri.parse("custom://"+System.currentTimeMillis())));
alarmManager.cancel(pendingIntent);
Calendar alarmStartTime = Calendar.getInstance();
Calendar now = Calendar.getInstance();
alarmStartTime.set(Calendar.HOUR_OF_DAY, 8);
alarmStartTime.set(Calendar.MINUTE, 00);
alarmStartTime.set(Calendar.SECOND, 0);
if (now.after(alarmStartTime)) {
Log.d("Hey","Added a day");
alarmStartTime.add(Calendar.DATE, 1);
}
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
alarmStartTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Log.d("Alarm","Alarms set for everyday 8 am.");
来到广播接收器类。您需要在清单中注册广播接收器。这将导致您接收时钟事件。 覆盖此广播接收器的 onReceive 方法并在那里自己发出通知或制作单独的通知构建服务并在那里构建和显示您的通知。
清单代码sn-p:
广播接收代码sn-p:
public class AlarmReceiver1 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent service1 = new Intent(context, NotificationService1.class);
service1.setData((Uri.parse("custom://"+System.currentTimeMillis())));
context.startService(service1);
}
通知构建服务代码sn-p:
public class NotificationService1 extends IntentService{
private NotificationManager notificationManager;
private PendingIntent pendingIntent;
private static int NOTIFICATION_ID = 1;
Notification notification;
@Override
protected void onHandleIntent(Intent intent) {
Context context = this.getApplicationContext();
notificationManager =
(NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, Activity to be opened after clicking on the
notif);
Bundle bundle = new Bundle();
bundle.putString("test", "test");
mIntent.putExtras(bundle);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
Resources res = this.getResources();
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
notification = new NotificationCompat.Builder(this)
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(res, R.drawable.ic_launcher))
.setTicker("ticker value")
.setAutoCancel(true)
.setPriority(8)
.setSound(soundUri)
.setContentTitle("Notif title")
.setContentText("Text").build();
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE;
notification.ledARGB = 0xFFFFA500;
notification.ledOnMS = 800;
notification.ledOffMS = 1000;
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notification);
Log.i("notif","Notifications sent.");
}
}
【讨论】:
使用 NotifyMe Android 库进行简单通知。当您希望弹出通知时,非常容易设置延迟或时间。系统重启后会弹出通知。
使用 Jitpack.io 下载库 将此添加到您的应用的 build.gradle 文件中。
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
将此添加到项目的 build.gradle 中的依赖项中。
dependencies {
implementation 'com.github.jakebonk:NotifyMe:1.0.1'
}
示例 创建一个 NotifyMe 构建器对象
NotifyMe.Builder notifyMe = new NotifyMe.Builder(getApplicationContext());
然后设置你想要的字段。
notifyMe.title(String title);
notifyMe.content(String content);
notifyMe.color(Int red,Int green,Int blue,Int alpha);//Color of notification header
notifyMe.led_color(Int red,Int green,Int blue,Int alpha);//Color of LED when
notification pops up
notifyMe.time(Calendar time);//The time to popup notification
notifyMe.delay(Int delay);//Delay in ms
notifyMe.large_icon(Int resource);//Icon resource by ID
notifyMe.rrule("FREQ=MINUTELY;INTERVAL=5;COUNT=2")//RRULE for frequency of
//notification
notifyMe.addAction(Intent intent,String text); //The action will call the intent when
//pressed
在你想要的所有字段都设置好之后,只需调用 build()!
notifyMe.build();
【讨论】: