如何在特定时间android发出通知?

How To give notifications on android on specific time?

我想在特定时间向我的应用程序发出通知。说每天早上7点通知,即使应用关闭了。

我该怎么做?任何教程? 请提及 link.

您可以使用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" />

首先你需要使用广播接收器。并且因为广播接收器只启动了很短的时间

from the android developer blog.When handling a broadcast, the application is given a fixed set of time (currently 10 seconds) in which to do its work. If it doesn't complete in that time, the application is considered to be misbehaving, and its process immediately tossed into the background state to be killed for memory if needed.

使用意向服务是更好的做法,这里有一个示例。

这是广播接收器class。

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>

这是意图服务 class。

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>

然后在你的 activity 中设置警报管理器在特定时间启动广播接收器并使用 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);

希望对您有所帮助。

由于后台服务限制 ( https://developer.android.com/about/versions/oreo/background.html#services) 并且当应用程序处于后台时会导致这样的异常:

java.lang.IllegalStateException: Not allowed to start service Intent xxx: app is in background

一种可能的解决方法是使用 JobIntentService:

  1. JobIntentService 而不是 IntentService 扩展你的 Service 并使用 onHandleWork 方法而不是 onHandleIntent.

  2. android:permission="android.permission.BIND_JOB_SERVICE" 添加到 AndroidManifest.xml 中的 Service

  • 从系统获取报警服务。
  • 创建一个待处理的意图,传入广播接收器class的名称。
  • 创建一个日历对象并将其时间设置为上午 8 点。
  • 检查当前时间是否超过 8。如果是,则再添加一天。
  • 调用AlarmManager的设置重复方法class。

相同的示例代码:

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.");

来到广播接收器class。您需要在清单中注册您的广播接收器。这将使您收到时钟事件。 覆盖此广播接收器的 onReceive 方法并在那里自己发出通知,或者制作一个单独的通知构建服务并在那里构建和显示您的通知。

清单代码片段:

广播接收器代码片段:

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);
}

通知构建服务代码片段:

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();

这是我的解决方案,已在 android10 上测试。还与 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_IDTIMELINE_CHANNEL_NAME 是在另一个 class 上创建的。

例如,

CHANNEL_ID = "notification channel";

TIMELINE_CHANNEL_NAME = "Timeline notification";

任何对我的代码和错误的误解,请不要犹豫发表评论。我会尽快回复。