我试图在用户选定的日期和时间收到通知,但收到此错误: 从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是你想要的吗?
我尝试将标志 FLAG_ACTIVITY_NEW_TASK 添加到意图中,但是如果我添加它,则通知将不会出现。在除 Android 14 之外的所有其他设备中都运行良好,我没有错误,即使应用程序被终止,通知也会显示,但在 Android 14 中它会崩溃。
有人知道如何修复它吗? 这是我的代码
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if ("android.intent.action.BOOT_COMPLETED" == intent.action) {
AlarmUtil.scheduleAll(context)
return
}
val dayOfWeek = intent.getIntExtra("Day", 2)
AlarmUtil.scheduleAlarm(context, dayOfWeek, AppPreferences.hourOfDay, AppPreferences.minuteOfDay, true)
val notificationId = Random().nextInt(60000)
val notificationManager =
context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
val channelId = App.instance.applicationContext.getString(R.string.message_notification_channel_id)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = App.instance.applicationContext.getString(R.string.message_notification_channel_name)
val descriptionText = App.instance.applicationContext.getString(R.string.message_notification_channel_name)
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(channelId, name, importance).apply {
description = descriptionText
enableLights(true)
enableVibration(true)
if (defaultSoundUri != null) {
val att = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build()
setSound(defaultSoundUri, att)
}
lightColor = Color.parseColor("#501450")
}
notificationManager.createNotificationChannel(channel)
}
val newIntent = Intent(context, StartActivity::class.java)
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
newIntent.action = "actionString" + System.currentTimeMillis()
val pendingIntent =
PendingIntent.getActivity(context, 0, newIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
val notificationBuilder = NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_notification)//a resource for your custom small icon
.setColor(Color.parseColor("#222831"))
.setContentText(App.instance.applicationContext.getString(R.string.remiderNotificationText))//ditto
.setAutoCancel(true) //dismisses the notification on click
.setSound(defaultSoundUri)
.setVibrate(LongArray(0))
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_MAX) // heads-up
.setContentIntent(pendingIntent)
notificationManager.notify(
notificationId /* ID of notification */,
notificationBuilder.build()
)
}
}
object AlarmUtil {
private val alarmManager = App.instance.applicationContext.getSystemService(Context.ALARM_SERVICE) as AlarmManager
fun scheduleAlarm(context: Context?, dayOfWeek: Int, hourOfTheDay: Int, minuteOfTheDay: Int, repeating: Boolean) {
val calendar = Calendar.getInstance()
when(dayOfWeek){
1 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.MONDAY
2 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.TUESDAY
3 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.WEDNESDAY
4 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.THURSDAY
5 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.FRIDAY
6 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.SATURDAY
7 -> calendar[Calendar.DAY_OF_WEEK] = Calendar.SUNDAY
}
calendar[Calendar.HOUR_OF_DAY] = hourOfTheDay
calendar[Calendar.MINUTE] = minuteOfTheDay
calendar[Calendar.SECOND] = 0
if(repeating || calendar.timeInMillis < System.currentTimeMillis()){
calendar.add(Calendar.DATE, 7)
}
val intent = Intent(context, AlarmReceiver::class.java)
intent.putExtra("Day", dayOfWeek)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val pendingIntent = PendingIntent.getBroadcast(context, dayOfWeek, intent, PendingIntent.FLAG_IMMUTABLE)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (!alarmManager.canScheduleExactAlarms()) {
Intent().also {
it.action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context?.startActivity(it)
}
}else {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
}
}
}
fun cancelAllAlarms(context: Context?) {
val intent = Intent(context, AlarmReceiver::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
AppPreferences.selectedDays.fromPrettyJson<Array<String>>().forEach {
val pendingIntent = PendingIntent.getBroadcast(context, it.toInt(), intent, PendingIntent.FLAG_IMMUTABLE)
alarmManager.cancel(pendingIntent)
}
}
fun scheduleAll(context: Context?) {
if(AppPreferences.userNotifications && AppPreferences.specialUserNotifications){
AppPreferences.selectedDays.fromPrettyJson<ArrayList<String>>().forEach {
scheduleAlarm(context, it.toInt(), AppPreferences.hourOfDay, AppPreferences.minuteOfDay, false)
}
}
}
}
class ReminderService : Service() {
override fun onBind(p0: Intent?): IBinder? {
return null
}
override fun onTaskRemoved(rootIntent: Intent) {
super.onTaskRemoved(rootIntent)
if(AppPreferences.selectedDays.isNotEmpty()){
if(AppPreferences.specialUserNotifications) {
AlarmUtil.scheduleAll(applicationContext)
} else {
AlarmUtil.cancelAllAlarms(applicationContext)
}
}
this.stopSelf()
}
}
class ReminderWorker(appContext: Context, workerParams: WorkerParameters) :
CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
// Check if app is in foreground
if (ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
val intent = Intent(applicationContext, ReminderService::class.java)
applicationContext.startService(intent)
}
return Result.success()
}
}
//This is on my main activity:
val workRequest = OneTimeWorkRequestBuilder<ReminderWorker>().build()
// Enqueue the work request
WorkManager.getInstance(this).enqueue(workRequest)
如果您的项目使用 Android Jetpack,请考虑使用 WorkManager。此 API 提供了一种更结构化的方式来安排后台任务,包括安排通知。