android - Android 8/9 通知调度
问题描述
我试图为特定日期和时间安排通知,但在大多数设备上似乎没有显示通知。在 android 9/8 之前,我使用了 AlarmManager,它非常易于使用并且可以正常工作,但是最近 2 个版本的 android 改变了这一点……(感谢 google 让一切变得更容易……)
所以,这是我的代码用于安排通知。我正在使用OneTimeWorkRequest
tag = new AlertsManager(this).getCarId(nrInmatriculare);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Data inputData = new Data.Builder().putString("type", alarmType).putString("nrInmatriculare", nrInmatriculare).build();
OneTimeWorkRequest notificationWork = new OneTimeWorkRequest.Builder(NotifyWorker.class)
.setInitialDelay(calculateDelay(when), TimeUnit.MILLISECONDS)
.setInputData(inputData)
.addTag(String.valueOf(tag))
.build();
WorkManager.getInstance().enqueue(notificationWork);
}
else {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, when, (24 * 60 * 60 * 1000), pendingIntent);
}
然后我用来显示通知的类是这样的:
public class NotifyWorker extends Worker {
public NotifyWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Worker.Result doWork() {
// Method to trigger an instant notification
new NotificationIntentService().showNotification(getInputData().getString("type"),getInputData().getString("nrInmatriculare"), getApplicationContext());
return Worker.Result.SUCCESS;
// (Returning RETRY tells WorkManager to try this task again
// later; FAILURE says not to try again.)
}
}
和这个 :
public class NotificationIntentService extends IntentService {
final Uri notificationSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
int alarmId = 0;
public NotificationIntentService() {
super("NotificationIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
showNotification(intent);
}
//show notification with workmanager
public void showNotification(String type, String nrInmatriculare, Context context){
try
{
if (!TextUtils.isEmpty(type) && !TextUtils.isEmpty(nrInmatriculare)) {
AlertsManager alertsManager = new AlertsManager(context);
Notifications notification = alertsManager.getAlertForCar(nrInmatriculare);
String text ="";
Calendar endDate = null;
String date = notification.EndDate.get(Calendar.YEAR) + "-" + (notification.EndDate.get(Calendar.MONTH)/10==0 ? "0"+(notification.EndDate.get(Calendar.MONTH)+1) : (notification.EndDate.get(Calendar.MONTH))+1) + "-" + (notification.EndDate.get(Calendar.DAY_OF_MONTH)/10==0 ? "0"+notification.EndDate.get(Calendar.DAY_OF_MONTH) : notification.EndDate.get(Calendar.DAY_OF_MONTH));
text = context.getString(R.string.notificationText).toString().replace("#type#", type.toUpperCase()).replace("#nrInmatriculare#", nrInmatriculare).replace("#date#", date ).replace("#days#", String.valueOf(new Utils().getDateDifferenceInDays(Calendar.getInstance(), notification.EndDate)));
alarmId = alertsManager.getCarId(nrInmatriculare);
endDate = (Calendar)notification.EndDate.clone();
if (Calendar.getInstance().getTimeInMillis() > endDate.getTimeInMillis()){ //current time is after the end date (somehow the alarm is fired)
}
else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//define the importance level of the notification
int importance = NotificationManager.IMPORTANCE_HIGH;
//build the actual notification channel, giving it a unique ID and name
NotificationChannel channel = new NotificationChannel("AppName", "AppName", importance);
//we can optionally add a description for the channel
String description = "A channel which shows notifications about events at Masina";
channel.setDescription(description);
//we can optionally set notification LED colour
channel.setLightColor(Color.MAGENTA);
// Register the channel with the system
NotificationManager notificationManager = (NotificationManager)context.
getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.createNotificationChannel(channel);
}
//---------
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "AppName");
builder.setContentTitle(context.getString(R.string.app_name));
builder.setContentText(text);
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setAutoCancel(true);
builder.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
builder.setLights(Color.CYAN, 1000, 2000);
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
builder.setSound(notificationSound);
builder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));
Intent notifyIntent = null;
if (type.equals("CarteDeIdentitate") || type.equals("PermisDeConducere"))
notifyIntent = new Intent(context, PersonalDataActivity.class);
else
notifyIntent = new Intent(context, DetailActivity.class);
notifyIntent.putExtra("car", new SharedPreference(context).getCarDetailString(nrInmatriculare));
// Create the TaskStackBuilder and add the intent, which inflates the back stack
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntentWithParentStack(notifyIntent);
//PendingIntent pendingIntent = PendingIntent.getActivity(context, alarmId, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(alarmId, PendingIntent.FLAG_UPDATE_CURRENT);
//to be able to launch your activity from the notification
builder.setContentIntent(pendingIntent);
//trigger the notification
NotificationManagerCompat notificationAlert = NotificationManagerCompat.from(context);
notificationManager.notify(alarmId, builder.build());
}
}
}
else
{
Log.d("here","No extra");
}
}
catch(Exception ex)
{
Log.d("here","Error");
}
}
}
我究竟做错了什么?有最好和更有效的方法吗?
编辑:我想看一个关于如何将通知安排到特定日期+时间的示例,这确实有效。
解决方案
这是我在我的一个项目中使用的一种工作实现。
将此添加到您的build.gradle (app)
(因为它在 Kotlin 中)
//android-jet pack
implementation 'android.arch.work:work-runtime-ktx:1.0.1'
或使用 Android X:
implementation "androidx.work:work-runtime-ktx:2.5.0"
https://developer.android.com/jetpack/androidx/releases/work
创建一个方法scheduleNotification
。传递您的必要数据
fun scheduleNotification(timeDelay: Long, tag: String, body: String) {
val data = Data.Builder().putString("body", body)
val work = OneTimeWorkRequestBuilder<NotificationSchedule>()
.setInitialDelay(timeDelay, TimeUnit.MILLISECONDS)
.setConstraints(Constraints.Builder().setTriggerContentMaxDelay(Constant.ONE_SECOND, TimeUnit.MILLISECONDS).build()) // API Level 24
.setInputData(data.build())
.addTag(tag)
.build()
WorkManager.getInstance().enqueue(work)
}
NotificationSchedule
班级
class NotificationSchedule (var context: Context, var params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
val data = params.inputData
val title = "Title"
val body = data.getString("body")
TriggerNotification(context, title, body)
return Result.success()
}
}
TriggerNotification
班级。根据您的需要自定义此类
class TriggerNotification(context: Context, title: String, body: String) {
init {
sendNotification(context, title, body)
}
private fun createNotificationChannel(context: Context, name: String, description: String): String {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
val chanelId = UUID.randomUUID().toString()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(chanelId, name, importance)
channel.enableLights(true)
channel.enableVibration(true)
channel.description = description
channel.lightColor = Color.BLUE
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
val notificationManager = context.getSystemService(NotificationManager::class.java)
notificationManager?.createNotificationChannel(channel)
}
return chanelId
}
private fun sendNotification(context: Context, title: String, body: String) {
val notificationManager = NotificationManagerCompat.from(context)
val mBuilder = NotificationCompat.Builder(context, createNotificationChannel(context, title, body))
val notificationId = (System.currentTimeMillis() and 0xfffffff).toInt()
mBuilder.setDefaults(Notification.DEFAULT_ALL)
.setTicker("Hearty365")
.setContentTitle(title)
.setContentText(body)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSmallIcon(R.drawable.icon)
.setContentInfo("Content Info")
.setAutoCancel(true)
notificationManager.notify(notificationId, mBuilder.build())
}
}
推荐阅读
- sql - SQL OpenJson - 无法在 json 中为 json 创建列
- r - 在 Lattice 的面板函数中使用 ifelse 或 if 循环不适用于 panel.xyplot
- azure-devops - Azure 发布 - 更改部署的活动阶段
- python - 从命令中保存附件
- javascript - HTML/JavaScript:如何在特殊 div 中重新创建文本位置/选择
- python - cv2.VideoWriter 和 GStreamer 的配置问题
- python - 使用 tf.profiler.experimental.client.trace 的 TensorFlow 分析器提供空的跟踪数据
- angular - Angular - 同一浏览器的选项卡之间的共享会话
- google-cloud-platform - 未结费用 Google Cloud Platform
- python - 处理 Python 中缺少非空断言运算符