简体   繁体   中英

AlarmManager and BroadcastReceiver where intent has no extra at all

I try to send notification in an exact time, therefore I added an AlarmManager. AlarmReceiver is triggered, the intent action is set, but has no extra at all.

I made a simple separated AlarmService class for the AlarmManager AlarmService.kt:

private const val TAG = "AlarmService"

class AlarmService @Inject constructor(
    @ApplicationContext private val context: Context
) {

    private val alarmManager: AlarmManager? =  context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    private fun getPendingIntent(intent: Intent): PendingIntent =
        PendingIntent.getBroadcast(
            context,
            0,//RandomUtil.getRandomInt(),
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT
        )


    fun reminderAlarm(timeInMillis: Long, item: CustomParcelable){
        val intent = Intent(context, AlarmReceiver::class.java)
        intent.apply {
            action = Constants.ACTION_SET_EXACT_ALARM_REMINDER
            putExtra(Constants.EXTRA_EXACT_ALARM_TIME, timeInMillis)
            putExtra(Constants.EXTRA_EXACT_ALARM_ITEM, CustomParcelable)
        }
        setAlarm(timeInMillis, getPendingIntent(intent))
    }


    private fun setAlarm(timeInMillis: Long, pendingIntent: PendingIntent){
        alarmManager?.let {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    timeInMillis,
                    pendingIntent
                )
            } else {
                alarmManager.setExact(
                    AlarmManager.RTC_WAKEUP,
                    timeInMillis,
                    pendingIntent
                )
            }
        }
    }

Eveything works fine, but when the AlarmReceiver is triggered, there is only the intent ACTION, and has NO extra data, even the time data, which is a LONG AlarmReceiver.kt:

private const val TAG = "AlarmReceiver"

class AlarmReceiver: BroadcastReceiver() {
    private lateinit var myNotification: MyNotification

    override fun onReceive(context: Context, intent: Intent) {
        Log.e(TAG, "onReceive: INTENT ------>>>>>>>---------->>>>>>>>>------->>>>>>>>>---------->>>>>>: "
                + intent.hasExtra(Constants.EXTRA_EXACT_ALARM_TIME) )
        when(intent.action){

            Constants.ACTION_SET_EXACT_ALARM_REMINDER -> {
                val time: Long = intent.getLongExtra(Constants.EXTRA_EXACT_ALARM_TIME, 0L)
                val item: CustomParcelable? = intent.getParcelableExtra(Constants.EXTRA_EXACT_ALARM_ITEM)
                Log.e(TAG, "onReceive: ------------@@@@@@@@@@@@*-------------@@@@@@@@@------------"
                        + item?.title + " reminder: " + item?.reminder + " t: " + time)

                if (item != null) {
                    myNotification = MyNotification(context)
                    myNotification.createReminderNotificationChannel(item)
                    myNotification.sendNotificationReminder(item)
                }
            }
        }
    }

}

The item I would like to pass in the intent is Parcelable:

Item:

@Parcelize
data class CustomParcelable(
    val title: String,
    val reminder: String
) : Parcelable {
}

The manifest files I use the required permissions, and would like to make the alarm available after making a phone reboot. AndroidManifest:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".receiver.AlarmReceiver"
    android:exported="true"
    android:enabled="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

I found the solution, how these works. Just add the Parcelable item to a bundle:

class AlarmService @Inject constructor(
    @ApplicationContext private val context: Context
    ) {
    
 ...
    fun reminderAlarm(timeInMillis: Long, item: CustomParcelable){
        val intent = Intent(context, AlarmReceiver::class.java)
        intent.apply {
            action = Constants.ACTION_SET_EXACT_ALARM_REMINDER
        }
        
        val bundle = Bundle()
        bundle.putParcelable(Constants.EXTRA_EXACT_ALARM_ITEM, item)

        intent.putExtra(Constants.EXTRA_EXACT_ALARM_DATA, bundle)

        
        setAlarm(timeInMillis, getPendingIntent(intent))
    }
}

Now in the receiver side, you access the intent extra:

class AlarmReceiver: BroadcastReceiver() {
    private lateinit var myNotification: MyNotification

    override fun onReceive(context: Context, intent: Intent) {
        val data: Bundle? = intent.getBundleExtra(Constants.EXTRA_EXACT_ALARM_DATA)

       
        when(intent.action){

            Constants.ACTION_SET_EXACT_ALARM_REMINDER -> {
                val data: Bundle? = intent.getParcelableExtra(Constants.EXTRA_EXACT_ALARM_DATA)
                val item: CustomParcelable? = null

                if (data != null){
                    item = data.getParcelable(Constants.EXTRA_EXACT_ALARM_ITEM)
                
                    if (item != null) {
                        myNotification = MyNotification(context)
                        myNotification.createReminderNotificationChannel(item)
                        myNotification.sendNotificationReminder(item)
                    }
                }
            }
        }
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM