项目需求
最近工作中遇到这样一个需求:
- 每周五定时从本地发送通知到设备上
- 如果用户中途重启或关机,也要求可以收到通知
问题拆分:
这个问题可以分成几个部分来解决
1. 定时任务
我是采用 AlarmManager 中 setRepeating 的方法来实现的。在测试的过程中发现间隔时间不固定, 但是这个功能对精度的要求不高, 可以使用。 其他的情况要好好斟酌再用哦。这里写的是每周五早上八点的闹钟。
Intent intent = new Intent(context, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 4000,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, 6);
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY * 7, pendingIntent);
2. 发送本地通知
AlarmManager 到时间后会触发 AlarmReceiver 来发送本地通知
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String channelId = "channelId";
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("title")
.setContentText("message")
.setAutoCancel(true)
.setStyle(new NotificationCompat.BigTextStyle().bigText("message”));
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
“com.android.demo.channel",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(1, notificationBuilder.build());
}
}
}
对了,不要忘记在AndroidManifest.xml里面注册你的AlarmReceiver!
<receiver android:name=".AlarmReceiver" />
如果你只是需要短时间的执行任务, 到这里就可以啦。 但是你还想要设备开机/重启后还能在后台继续执行任务的话,请继续看下去吧
3. 监听设备开机/重启状态
这里同样需要一个BroastcastReceiver来监听这个事件。首先要在AndroidManifest.xml加监听权限, 并注册BroastcastReceiver。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.demo">
//...
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application>
//...
<receiver
android:name=".RebootBroadcastReceiver"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</manifest>
RebootBroadcastReceiver.java
public class RebootBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null) {
if (action.equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED)) {
//这里可以放AlarmManager的代码
//同1. 这里就不贴了
//或者startService()的代码
Intent i = new Intent(context, AlarmService.class);
ComponentName service;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
service = context.startForegroundService(i);
} else {
service = context.startService(i);
}
if (service == null) {
Log.i("RebootBroadcastReceiver", "Fail");
} else {
Log.i("RebootBroadcastReceiver", "Success");
}
}
}
}
}
4. 开启服务
要注意的是BroastcastReceiver 的onReceive最多可以执行5s,否则就会崩溃。所以如果业务逻辑比较麻烦,所以我用Service来处理。
public class AlarmService extends Service {
@Override
public void onCreate() {
super.onCreate();
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, "devicereboot")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle(getResources().getString(R.string.app_name))
.setContentText("is running background.")
.setAutoCancel(true);
NotificationManager notificationManager =
(NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("devicereboot",
"com.android.demo.devicereboot",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
startForeground(5000, notificationBuilder.build());
//这部分代码同1.
//也可替换成其他业务代码
Intent i = new Intent(this, AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 4000, i, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, 6);
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent);
//stopForeground()后,AlarmManager还在运行
//”devicereboot“通知会显示后被取消
stopForeground(true);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
总结:
到这里就告一段落啦, 基本满足项目需求。Android菜鸡一只,记录下平时遇到的疑点难点, 有问题的话多多指正。要加油啊!
版权声明:本文为weixin_43233524原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。