Afin d’exécuter des tâches répétitives il est possible d’utiliser l’AlarmManager qui permet de planifier des travaux à une heure et/ou date. A partir de l’API 21 un JobScheduler permet de planifier des travaux dépendant de certains états du périphérique (connecté au wifi,…)
AlarmManager :
1°) Définition :
AlarmManager
est la classe qui est utilisée pour les alarmes. Elle permet d’exécuter du code et peut être activée en dehors de l’application qui la générée,- Une alarme peut se déclencher même si le périphérique est en veille,
- Attention à la consommation de batterie, ne pas créer trop d’alarmes et trop fréquentes,
- Once an Alarm Started, this will execute until it is stopped explicitly or until device reboots.
- La classe AlarmManger vous permet de lancer un
Intent,
et peut être utilisée avec des
broadcast receivers.
2°) Mise en oeuvre :
- Android autorise 2 types d’Alarme : Une basée sur le temps réel (RTC) et l’autre sur le temps écoulé,
- Le temps écoulé est calculé à partir du dernier boot du périphérique,
- RTC est basé sur l’horloge du périphérique.
Pour définir une alarme
L’alarme peut par exemple déclencher un BroadCast :
package com.andrologiciels.androalarmtest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// For our recurring task, we'll just display a message
Toast.makeText(context, "I'm running", Toast.LENGTH_SHORT).show();
}
}
Initialisation de l’Alarme :
a) A un interval précis (en millisecondes ) :
public void start() {
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 8000;
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
}
Le fichier manifest (rien de particulier comme permission sauf pour le boot et le broadcast receiver) :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.andrologiciels.androalarmtest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MyActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".AlarmReceiver" >
</receiver>
<receiver
android:name=".DeviceBootReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
</application>
</manifest>
ATTENTION :
Pour un réveil à un horaire donné avec une répétition sur un interval :
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 30 * 1; // every 30s repeat
int nHour = 14;
int nMin = 30;
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, nHour);
calendar.set(Calendar.MINUTE, nMin);
// -- Attention, récuparation pour init de l'heure du jour
if (calendar.getTimeInMillis() < System.currentTimeMillis()) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
Toast.makeText(this, "Alarm Scheduled at " + nHour + ":" + nMin,
Toast.LENGTH_SHORT).show();
/* Repeating on an interval */
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), interval, pendingIntent);
Alarme au démarrage :
Les alarmes sont annulées lorsqu le téléphone est éteinds. Pour lancer une alarme au démarrage il est nécessaire de :
1°) Ajouter au manifest :
<uses-permission android:name= »android.permission.RECEIVE_BOOT_COMPLETED » />
<uses-permission android:name= »android.permission.WAKE_LOCK » />
et
<receiver android:name= ».DeviceBootReceiver » >
<intent-filter>
<action android:name= »android.intent.action.BOOT_COMPLETED » />
<category android:name= »android.intent.category.LAUNCHER » />
<action android:name= »android.intent.action.QUICKBOOT_POWERON » />
</intent-filter>
</receiver>
et
<service android:name= ».serviceAlarm » >
</service>
2°) Ecrire la procédure onBootReceiver :
public class DeviceBootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
WakefulIntentService.acquireStaticLock(context); // --acquire a partial WakeLock //
context.startService(new Intent(context, serviceAlarm.class)); // --start serviceAlarm
}
}
3°) Ajouter un wake lock pour réveiller le téléphone
package com.andrologiciels.androalarmtest;
import android.annotation.SuppressLint;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
/**
* Acquires a partial WakeLock, allows Service to keep the CPU alive
* until the work is done.
*/
@SuppressLint("Wakelock")
public class WakefulIntentService extends IntentService {
public static final String
LOCK_NAME_STATIC="com.andologiciels.androalarmtest.serviceAlarm.Static";;
public static final String
LOCK_NAME_LOCAL="com.andologiciels.androalarmtest.serviceAlarm.Local";
private static PowerManager.WakeLock lockStatic=null;
private PowerManager.WakeLock lockLocal=null;
public WakefulIntentService(String name) {
super(name);
}
/**
* Acquire a partial static WakeLock, you need too call this within the class
* that calls startService()
* @param context
*/
public static void acquireStaticLock(Context context) {
getLock(context).acquire();
}
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (lockStatic==null) {
PowerManager
mgr=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
lockStatic=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
LOCK_NAME_STATIC);
lockStatic.setReferenceCounted(true);
}
return(lockStatic);
}
@Override
public void onCreate() {
super.onCreate();
PowerManager mgr=(PowerManager)getSystemService(Context.POWER_SERVICE);
lockLocal=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
LOCK_NAME_LOCAL);
lockLocal.setReferenceCounted(true);
}
@Override
public void onStart(Intent intent, final int startId) {
lockLocal.acquire();
super.onStart(intent, startId);
getLock(this).release();
}
@Override
protected void onHandleIntent(Intent intent) {
lockLocal.release();
}
}
4°) Le service qui lance l’alarme
package com.andrologiciels.androalarmtest;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class serviceAlarm extends WakefulIntentService {
private PendingIntent pendingIntent;
public serviceAlarm() {
super("serviceAlarm");
}
@Override
protected void onHandleIntent(Intent intent) {
/* Retrieve a PendingIntent that will perform a broadcast */
Intent alarmIntent = new Intent(serviceAlarm.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(serviceAlarm.this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval = 1000 * 30 * 1; //30 secondes
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
Toast.makeText(this, "Alarm Set", Toast.LENGTH_SHORT).show();
super.onHandleIntent(intent);
}
}
5°) Et la classe contenant l’action à effectuer au lancement de l’alarme :
package com.andrologiciels.androalarmtest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// For our recurring task, we'll just display a message
Toast.makeText(context, "Alarm is running...", Toast.LENGTH_SHORT).show();
}
}
Liste des alarmes actives :
Branchez le terminale et tapez dans une fenêtre système (cmd) :
..\sdk\platform-tools>adb shell dumpsys alarm > dump.txt
Editez le fichier dump.txt et recherchez le package qui a lancé l’alarme, exemple :
RTC #4: Alarm{41c6dcc0 type 1 com.andrologiciels.andronameday}
type=1 originalType=0 when=+23m37s104ms repeatInterval=3600000 count=1
Ici l’on voit que l’alarme va être lancée dans 23′ et quelle sera répétée toutes les heures (3600000 millisecondes)
https://www.unitjuggler.com/convertir-time-de-ms-en-h.html?val=3600000
Références :
http://blog.masconsult.eu/blog/2014/01/17/scheduling-alarms/
http://developer.android.com/reference/android/app/AlarmManager.html#ELAPSED_REALTIME
https://developer.android.com/training/scheduling/alarms.html#type
Alarme : http://javatechig.com/android/repeat-alarm-example-in-android
Scheduler : http://www.vogella.com/tutorials/AndroidTaskScheduling/article.html#schedulestasks_jobscheduler
Liste des alarmes actives : http://stackoverflow.com/questions/6522792/get-list-of-active-pendingintents-in-alarmmanager
http://www.101apps.co.za/articles/scheduling-android-s-repeating-alarms.html
https://dhimitraq.wordpress.com/2012/11/27/using-intentservice-with-alarmmanager-to-schedule-alarms/
http://stackoverflow.com/questions/26380534/broadcastreceiver-vs-wakefulbroadcastreceiver
Et au sujet de wakefull :
https://randling.wordpress.com/2013/12/29/wakeful-and-repeatable-background-service-on-android/
http://stackoverflow.com/questions/7845660/how-to-run-a-service-every-day-at-noon-and-on-every-boot
Votre commentaire