Comment utiliser Android AlarmManager dans Fragment dans Kotlin?

Oct 08 2020

Je n'arrive pas à faire fonctionner AlarmManager dans un fragment. La méthode onReceive () de mon récepteur n'est jamais exécutée. Je suppose que je pourrais utiliser le contexte d'une mauvaise manière, mais encore une fois, je ne pouvais pas non plus le faire fonctionner dans une activité. J'ai également enregistré le destinataire dans mon manifeste.

MyFragment.kt

class MyFragment : Fragment() {

...

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

        super.onViewCreated(view, savedInstanceState)

        var alarmMgr: AlarmManager? = null
        lateinit var alarmIntent: PendingIntent

        alarmMgr = context!!.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmIntent = Intent(context, Receiver::class.java).let { intent ->

                PendingIntent.getService(context, 0, intent, 0)

        }

        val calendar: Calendar = Calendar.getInstance().apply {

        timeInMillis = System.currentTimeMillis()

        // The EditText includes a time in 24-hour format (e.g. 12:34)
        set(Calendar.HOUR_OF_DAY, editText.text.toString().substringBefore(":").toInt())
        set(Calendar.MINUTE, editText.text.toString().substringAfter(":").toInt())

        }

        Log.d("ALARM", "CREATED")

        alarmMgr?.set(
              AlarmManager.RTC,
              calendar.timeInMillis,
              alarmIntent
        )

    }

}

Receiver.kt

class Receiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {

        Log.d("ALARM", "RECEIVED")

    }

}

AndroidManifest.xml

<application
...
    <receiver android:name="com.example.name.Receiver" />
</application>

Réponses

1 Rey Oct 08 2020 at 18:33

Tout d'abord:

AndroidManifest.xml

<receiver
  android:name="com.example.name.Receiver"
  android:enabled="true"
  android:exported="true">
   <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
    <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
   </intent-filter>
</receiver>

Ensuite, dans ce cas dans votre Fragment, cependant, je suggère de faire ceci ailleurs:

val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, Receiver::class.java)

// Used for filtering inside Broadcast receiver
intent.action = "MyBroadcastReceiverAction"
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)

// In this particular example we are going to set it to trigger after 30 seconds.
// You can work with time later when you know this works for sure.
val msUntilTriggerHour: Long = 30000
val alarmTimeAtUTC: Long = System.currentTimeMillis() + msUntilTriggerHour

// Depending on the version of Android use different function for setting an 
// Alarm.
// setAlarmClock() - used for everything lower than Android M
// setExactAndAllowWhileIdle() - used for everything on Android M and higher
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
  alarmManager.setAlarmClock(
  AlarmManager.AlarmClockInfo(alarmTimeAtUTC, pendingIntent),
  pendingIntent
  )
} else {
  alarmManager.setExactAndAllowWhileIdle(
  AlarmManager.RTC_WAKEUP,
  alarmTimeAtUTC,
  pendingIntent
  )
}

Dans votre récepteur de diffusion, nous effectuons ensuite les opérations suivantes:

class Receiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        // We use this to make sure that we execute code, only when this exact 
        // Alarm triggered our Broadcast receiver
        if (intent?.action == "MyBroadcastReceiverAction") {
           Log.d("ALARM", "RECEIVED")
        }
    }
}