问题
I try to create daily notification for my application. In order to test the application I set the interval for the notifications to 15 minutes. Unfortunately, no notification is shown. Neither when the application is running nor when it is closed. I tried to inspire myself with these solutions:
https://stackoverflow.com/questions/33055129/how-to-show-a-notification-everyday-at-a-certain-time-even-when-the-app-is-close
https://developer.android.com/codelabs/android-training-alarm-manager#0
https://github.com/google-developer-training/android-fundamentals-apps-v2/tree/master/StandUp (repository for the previous link)
I added uses-permissions and receiver to the manifest file.
manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ovu">
<uses-permission android:name = "android.permission.VIBRATE" />
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<!-- Permission to start Alarm on device reboot -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
...
</activity>
<receiver android:name= ".DailyNotificationReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>
This class extends BroadcastReceiver class and overrides onReceive method.
DailyNotificationReceiver
class DailyNotificationReceiver : BroadcastReceiver() {
companion object {
// Notification ID.
private const val NOTIFICATION_ID = 0
// Notification channel ID.
private const val PRIMARY_CHANNEL_ID = "primary_notification_channel"
}
private lateinit var mNotificationManager: NotificationManager
private val notificationContent = "Please measure your temperature and cervical mucus"
private val contentTitle = "Provide me your temperature and cervical mucus!"
override fun onReceive(context: Context, intent: Intent) {
mNotificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Deliver the notification.
deliverNotification(context);
}
private fun deliverNotification(context: Context) {
val contentIntent = Intent(context, MainActivity::class.java)
val contentPendingIntent = PendingIntent.getActivity(context, NOTIFICATION_ID, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT)
// Build the notification
val builder = NotificationCompat.Builder(context, PRIMARY_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_dialog_alert)
.setContentTitle(contentTitle)
.setContentText(notificationContent)
.setContentIntent(contentPendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
// Deliver the notification
mNotificationManager.notify(NOTIFICATION_ID, builder.build())
}
}
In this activity, instance of AlarmManager should set daily repeating.
ActivityNotification
class ActivityNotification : AppCompatActivity() {
companion object {
// Notification ID.
private const val NOTIFICATION_ID = 0
// Notification channel ID.
private const val PRIMARY_CHANNEL_ID = "primary_notification_channel"
}
private lateinit var mNotificationManager: NotificationManager
private fun notifyUser(){
val notifyIntent = Intent(this, DailyNotificationReceiver::class.java)
val notifyPendingIntent = PendingIntent.getBroadcast(this, NOTIFICATION_ID, notifyIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val repeatInterval = AlarmManager.INTERVAL_FIFTEEN_MINUTES
val triggerTime = (SystemClock.elapsedRealtime()
+ repeatInterval)
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
triggerTime, repeatInterval,
notifyPendingIntent)
// Create the notification channel.
createNotificationChannel();
Toast.makeText(this, "Alarm's set", Toast.LENGTH_LONG).show()
}
private fun createNotificationChannel() {
// Create a notification manager object.
mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
// Notification channels are only available in OREO and higher.
// So, add a check on SDK version.
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.O) {
// Create the NotificationChannel with all the parameters.
val notificationChannel = NotificationChannel(PRIMARY_CHANNEL_ID,
"Stand up notification",
NotificationManager.IMPORTANCE_HIGH)
notificationChannel.enableLights(true)
notificationChannel.lightColor = Color.RED
notificationChannel.enableVibration(true)
notificationChannel.description = "Notifies every 15 minutes to " +
"stand up and walk"
mNotificationManager.createNotificationChannel(notificationChannel)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_notification)
editTextNotificationHour = findViewById(R.id.editTextChangedNotification)
mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
}
fun changeNotificationHour(view: View){
notifyUser()
val intent = Intent(this, ProfileActivity::class.java)
startActivity(intent)
finish()
}
I'd be really happy if you guys can help me to find the solution.
回答1:
Firstly, let's start by enabling our BroadcastReceiver in Manifest by changing our code to this:
<receiver
android:name= ".DailyNotificationReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Secondly, I am a bit unsure of the purpose of the ActivityNotification
Activity.
It would be more than enough to create a simple class like Alarms
.
From there you can define all the methods you need to set up an alarm. Something like this:
class InternetDaysLeftAlarm @Inject constructor(
@ApplicationContext val context: Context
) {
/**
* Function is used to schedule one-time Alarm that will trigger on specific time.
*
* @param hourOfDay -> parameter defines what o'clock should the alarm be triggered at. (24-hour)
* default value is:
* @see INTERNET_DAYS_LEFT_ALARM_DEFAULT_TRIGGER_HOUR
*/
fun scheduleAlarm(hourOfDay: Int = INTERNET_DAYS_LEFT_ALARM_DEFAULT_TRIGGER_HOUR) {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, InternetDaysLeftReceiver::class.java)
intent.action = INTENT_ACTION_INTERNET_DAYS_LEFT_ALARM
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)
val msUntilTriggerHour: Long = TimeUnit.MINUTES.toMillis(minutesUntilOClock(hourOfDay))
// Calculating and adding jitter in order to ease load on server
val jitter: Long = TimeUnit.MINUTES.toMillis(Random.nextInt(0, 420).toLong())
val alarmTimeAtUTC: Long = System.currentTimeMillis() + msUntilTriggerHour + jitter
// Enabling BootReceiver
val bootReceiver = ComponentName(context, BootReceiver::class.java)
context.packageManager.setComponentEnabledSetting(
bootReceiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
/**
* Schedules the Alarm based on Android Version.
*
* As per AlarmManager documentation to guarantee Alarm execution at specified time we use following methods:
*
* @see AlarmManager.setExactAndAllowWhileIdle -> Android.M [API 23] and above.
* @see AlarmManager.setAlarmClock -> Everything below Android M.
*/
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTimeAtUTC, pendingIntent)
} else {
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(alarmTimeAtUTC, pendingIntent), pendingIntent)
}
}
Notifications can be handle by:
- Creating a separate
Notifications
class
or
- Handling all the notification things like creating channel and sending them inside
BroadcastReceiver
when you receive an Alarm.
来源:https://stackoverflow.com/questions/64805288/alarmmanager-with-notification-in-android-does-not-show-any-notifications