{"id":12200,"date":"2017-01-10T19:30:19","date_gmt":"2017-01-10T18:30:19","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=12200"},"modified":"2017-01-10T19:30:19","modified_gmt":"2017-01-10T18:30:19","slug":"gestire-allarmi-e-notifiche-nelle-applicazioni-android","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/gestire-allarmi-e-notifiche-nelle-applicazioni-android\/","title":{"rendered":"Gestire allarmi e notifiche nelle applicazioni Android"},"content":{"rendered":"<p>Quando si inizia a <strong>programmare in Android<\/strong>, ci si abitua a veder funzionare il proprio codice all&#8217;interno di un&#8217;applicazione. Eppure le API messe a disposizione ci permettono di interagire con il sistema operativo in una moltitudine di tempistiche.<\/p>\n<p>In questo post, ci occupiamo di far attivare delle operazioni in tempi prestabiliti anche se la nostra applicazione non \u00e8 in uso da parte dell&#8217;utente. Allo scattare di questo &#8220;allarme&#8221; verr\u00e0 invocato del nostro codice che potr\u00e0 svolgere qualsiasi operazione anche se, nel nostro caso, riguarder\u00e0 per lo pi\u00f9 l&#8217;apparizione di una notifica nella status bar. Pertanto, nell&#8217;esempio che segue (il cui codice \u00e8 scaricabile <a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/EsempioGestioneAllarmi.zip\">qui<\/a>) \u00a0vedremo al lavoro insieme tre tipi di componenti:<\/p>\n<ul>\n<li>l&#8217;<strong>AlarmManager<\/strong>, servizio di sistema che permette di attivare in momenti precisi o a intervalli prestabiliti una determinata azione ;<\/li>\n<li>un <strong>BroadcastReceiver<\/strong>, componente che ha la capacit\u00e0 di restare dormiente finch\u00e8 non viene attivata da un messaggio (in questo caso lanciato dall&#8217;AlarmManager);<\/li>\n<li>il <strong>NotificationManager<\/strong>, altro servizio di sistema, specializzato nel far apparire notifiche nella barra di stato del dispositivo.<\/li>\n<\/ul>\n<h2>AlarmManager: tempistiche di attivazione<\/h2>\n<p>L&#8217;AlarmManager permette di attivare del codice al momento richiesto. Avr\u00e0 bisogno di ricevere nostre istruzioni riguardanti le tempistiche e le modalit\u00e0 di attivazione ed un Intent che descrive l&#8217;azione da intraprendere.<\/p>\n<p>Per avere a disposizione un&#8217;istanza dell&#8217;AlarmManager faremo questo:<\/p>\n<pre class=\"lang:java decode:true\">AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);<\/pre>\n<p>e, nel momento della necessit\u00e0, invocheremo un suo metodo per richiedere la temporizzazione di funzionalit\u00e0:<\/p>\n<pre class=\"lang:java decode:true \">int intervallo = 10000;\r\nmanager.setInexactRepeating(AlarmManager.RTC_WAKEUP, \r\n                               System.currentTimeMillis(), \r\n                                   intervallo, \r\n                                       pendingIntent);<\/pre>\n<p>In questo caso, si richiede l&#8217;impostazione di un allarme periodico a partire da ora (<em>System.currentTimeMillis<\/em>) che scatti ogni 10 secondi (i millisecondi impostati nella variabile <em>intervallo<\/em>). L&#8217;allarme \u00e8 di tipo <strong>RTC<\/strong> ossia scatta all&#8217;ora impostata, in alternativa si pu\u00f2 utilizzare un allarme di tipo <strong>ELAPSED_REALTIME<\/strong> che si innesca dopo un determinato periodo di tempo contato a partire dal boot di sistema.<\/p>\n<p>Il riferimento <em>pendingIntent<\/em> che appare come ultimo parametro rappresenta l&#8217;azione che deve essere svolta ad ogni allarme ed \u00e8 di classe <strong>PendingIntent<\/strong>. Possiamo considerare questi oggetti dei contenitori di Intent che li conservano\u00a0lasciandoli in sospeso fino al momento dell&#8217;attivazione.<\/p>\n<h2>BroadcastReceiver: attivazione di codice su richiesta<\/h2>\n<p>Il BroadcastReceiver viene creato come una normale classe Java che vede al suo interno\u00a0solo un metodo, <em>onReceive<\/em>, contenente il codice da attivare al momento della ricezione di un Intent. Nel nostro esempio, questo Intent da inviare sar\u00e0 consegnato all&#8217;AlarmManager incapsulato nel\u00a0PendingIntent.<\/p>\n<p>Questa la struttura di un BroadcastReceiver:<\/p>\n<pre class=\"lang:java decode:true \">public class MyReceiver extends BroadcastReceiver {\r\n\r\n    @Override\r\n    public void onReceive(Context context, Intent intent) {\r\n\r\n       \/*\r\n        * codice da eseguire al momento dell'attivazione\r\n        *\/\r\n\r\n    }\r\n}<\/pre>\n<p>Come si vede, l&#8217;implementazione di un componente simile \u00e8 banalissima. Il metodo <em>onReceive<\/em> ricever\u00e0 in input un riferimento al Context per poter avviare qualunque richiesta nel sistema ed un Intent, quello con cui \u00e8 stato attivato il Receiver.<\/p>\n<p>Da non dimenticare che un BroadcastReceiver, in quanto componente dell&#8217;applicazione, va dichiarato nel file AndroidManifest.xml:<\/p>\n<pre class=\"lang:xhtml decode:true\">&lt;manifest xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    package=\"....\"&gt;\r\n\r\n    &lt;application\r\n       ... \r\n      &gt;\r\n\r\n        &lt;receiver\r\n            android:name=\".MyReceiver\"\r\n            android:enabled=\"true\"\r\n            android:exported=\"false\" \/&gt;\r\n\r\n    &lt;\/application&gt;\r\n\r\n&lt;\/manifest&gt;<\/pre>\n<p>dove, essenzialmente non passeremo altro che il nome della classe che rappresenta il Receiver.<\/p>\n<h2>NotificationManager: informare l&#8217;utente al momento giusto<\/h2>\n<p>Nel nostro esempio, all&#8217;interno del metodo onReceive del BroadcastReceiver, richiederemo l&#8217;apparizione di una notifica all&#8217;utente e lo faremo cos\u00ec:<\/p>\n<pre class=\"lang:java decode:true\">  NotificationCompat.Builder builder =\r\n                new NotificationCompat.Builder(context)\r\n                        .setSmallIcon(android.R.drawable.ic_dialog_alert)\r\n                        .setContentTitle(\"Titolo della notifica\")\r\n                        .setContentIntent(resultPendingIntent)\r\n                        .setContentText(\"Descrizione dell'evento\");\r\n<\/pre>\n<p>Con il Builder costruiremo la notifica ma non la faremo ancora apparire. Quello che si vede nel codice richieder\u00e0 che la nostra notifica abbia un titolo, un testo, un&#8217;icona piccola ed un&#8217;azione da svolgere attivata al momento in cui la notifica stessa venga cliccata: anche questa azione pronta all&#8217;uso viene impacchettata in un PendingIntent.<\/p>\n<p>Per quanto riguarda, l&#8217;apparizione della notifica dovremo utilizzare il seguente servizio di sistema:<\/p>\n<pre class=\"lang:java decode:true\">NotificationManager manager =\r\n                (NotificationManager) \r\n                       context.getSystemService(Context.NOTIFICATION_SERVICE);\r\nmanager.notify(NOTIFICATION_ID, builder.build());<\/pre>\n<p>dove il metodo <em>notify<\/em> non chiede altro che un identificativo numerico che contraddistingua la notifica e il risultato del metodo <em>build<\/em> invocato sull&#8217;oggetto <em>builder<\/em> con cui abbiamo preparato la notifica.<\/p>\n<h2>L&#8217;esempio: mettiamo tutto insieme<\/h2>\n<p>La nostra applicazione di esempio sar\u00e0 molto semplice: un layout con due pulsanti di cui il primo &#8211; etichettato come &#8220;Attiva allarme&#8221; &#8211; indicher\u00e0 al sistema di &#8220;svegliare&#8221; il nostro BroadcastReceiver ogni dieci secondi ed il secondo &#8211; chiamato &#8220;Ferma allarme&#8221; &#8211; servir\u00e0 a disattivare tali segnalazioni. L&#8217;aspetto interessante \u00e8 che la gestione degli avvisi \u00e8 totalmente demandata al sistema operativo, per mezzo dell&#8217;AlarmManager, quindi la loro propagazione sar\u00e0 indipendente dalla nostra Activity che, nel frattempo potr\u00e0 essere chiusa.<\/p>\n<p>Ecco il layout:<\/p>\n<pre class=\"lang:xhtml decode:true \">&lt;LinearLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\r\n    android:padding=\"10dp\"\r\n    android:orientation=\"vertical\"&gt;\r\n\r\n    &lt;Button android:layout_width=\"wrap_content\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_gravity=\"center_horizontal\"\r\n        android:layout_marginTop=\"20dp\"\r\n        android:text=\"Attiva allarme\"\r\n        android:onClick=\"impostaAllarme\"\/&gt;\r\n\r\n    &lt;Button android:layout_width=\"wrap_content\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_gravity=\"center_horizontal\"\r\n        android:layout_marginTop=\"20dp\"\r\n        android:text=\"Ferma allarme\"\r\n        android:onClick=\"cancellaAllarme\"\/&gt;\r\n  &lt;\/LinearLayout&gt;<\/pre>\n<p>e questo il risultato che produrr\u00e0:<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_01.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12208\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_01.jpg\" alt=\"android-alarmmanager-notification-broadcastreceiver_img_01\" width=\"480\" height=\"425\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_01.jpg 480w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_01-300x266.jpg 300w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/a><\/p>\n<p>I pulsanti attiveranno i metodi dell&#8217;Activity <em>impostaAllarme<\/em> e <em>cancellaAllarme<\/em> il cui effetto sar\u00e0 quello di interagire con il servizio AlarmManager come accennato in precedenza:<\/p>\n<pre class=\"lang:java decode:true \">public class MainActivity extends AppCompatActivity {\r\n\r\n    private PendingIntent pendingIntent;\r\n\r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n        setContentView(R.layout.activity_main);\r\n\r\n        Intent intent = new Intent(this, AlarmReceiver.class);\r\n        pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);\r\n\r\n    }\r\n\r\n    public void impostaAllarme(View v)\r\n    {\r\n        AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);\r\n        int intervallo = 10000;\r\n\r\n        manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), intervallo, pendingIntent);\r\n        Toast.makeText(this, \"Attivato!\", Toast.LENGTH_SHORT).show();\r\n    }\r\n\r\n    public void cancellaAllarme(View v)\r\n    {\r\n        AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);\r\n        manager.cancel(pendingIntent);\r\n        Toast.makeText(this, \"Cancellato!\", Toast.LENGTH_SHORT).show();\r\n    }\r\n}\r\n<\/pre>\n<p>A tal proposito, si noti che per cancellare un allarme gi\u00e0 impostato \u00e8 necessario invocare il metodo <em>cancel<\/em> passando un PendingIntent che si riferisce alla medesima azione.<\/p>\n<p>Nell&#8217;<em>onCreate<\/em>, \u00a0il PendingIntent viene inizializzato con il metodo <em>getBroadcast<\/em> che mirer\u00e0 ad attivare il BroadcastReceiver che definiremo cos\u00ec:<\/p>\n<pre class=\"\">public class AlarmReceiver extends BroadcastReceiver {\r\n\r\n    private static final int NOTIFICATION_ID = 5555;\r\n    @Override\r\n    public void onReceive(Context context, Intent intent) {\r\n\r\n        Intent actionIntent = new Intent(context, MainActivity.class);\r\n\r\n        PendingIntent pending =\r\n                PendingIntent.getActivity(\r\n                        context,\r\n                        0,\r\n                        actionIntent,\r\n                        PendingIntent.FLAG_UPDATE_CURRENT\r\n                );\r\n\r\n        NotificationCompat.Builder builder =\r\n                new NotificationCompat.Builder(context.getApplicationContext())\r\n                        .setSmallIcon(android.R.drawable.ic_dialog_alert)\r\n                        .setContentTitle(\"Orario: \"+new Date().toString())\r\n                        .setContentIntent(pending)\r\n                        .setContentText(\"Allarme scattato...\");\r\n\r\n\r\n        NotificationManager manager =\r\n                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);\r\n        manager.notify(NOTIFICATION_ID, builder.build());\r\n\r\n    }\r\n}<\/pre>\n<p>Nel metodo <em>onReceive<\/em>, prepareremo la notifica per l&#8217;utente, l&#8217;attiveremo e, mediante l&#8217;azione impostata al suo interno, si potr\u00e0 richiamare l&#8217;Activity per interrompere la schedulazione degli allarmi cliccando sul tasto &#8220;Ferma allarme&#8221;.<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_02.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12209\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_02.jpg\" alt=\"android-alarmmanager-notification-broadcastreceiver_img_02\" width=\"478\" height=\"214\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_02.jpg 478w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2016\/06\/android-alarmmanager-notification-broadcastreceiver_img_02-300x134.jpg 300w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><\/a><\/p>\n<p>Il semplice esempio visto in questo post non fa nulla di particolare ma imposta un&#8217;architettura minimale di uno schema molto ricorrente: attivazione secondo tempistiche proprie di un allarme (singolo o ricorrente), attivazione di codice anche quando l&#8217;applicazione non \u00e8 in uso, svolgimento delle operazioni e, al termine,\u00a0ove\u00a0necessarie, attivit\u00e0 di notifica all&#8217;utente. Il tutto potr\u00e0 essere personalizzato per i propri scopi, anche solo sostituendo il codice contenuto all&#8217;interno del metodo <em>onReceive<\/em> del BroadcastReceiver.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quando si inizia a programmare in Android, ci si abitua a veder funzionare il proprio codice all&#8217;interno&#8230;<\/p>\n","protected":false},"author":561,"featured_media":12716,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1682,1],"tags":[1842,1843,1278,1845,1844,1841],"class_list":["post-12200","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-tutorial-pratici","tag-alarm-android","tag-alarmmanager","tag-android","tag-broadcastreceiver","tag-notificationmanager","tag-notifiche-android"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/12200","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/561"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=12200"}],"version-history":[{"count":10,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/12200\/revisions"}],"predecessor-version":[{"id":12717,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/12200\/revisions\/12717"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media\/12716"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=12200"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=12200"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=12200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}