{"id":12874,"date":"2017-05-11T16:15:19","date_gmt":"2017-05-11T14:15:19","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=12874"},"modified":"2017-05-11T16:15:19","modified_gmt":"2017-05-11T14:15:19","slug":"content-provider-introduzione-alla-condivisione-di-dati-in-android","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/content-provider-introduzione-alla-condivisione-di-dati-in-android\/","title":{"rendered":"Content Provider: introduzione alla condivisione di dati in Android"},"content":{"rendered":"<p>Tutte le applicazioni Android devono avere cura dei dati che gestiscono, in qualunque maniera siano immagazzinati. Considerando che nessuna app pu\u00f2 mettere le mani nelle informazioni custodite da un&#8217;altra \u00e8 previsto un meccanismo ufficiale di sistema per la condivisione di dati: i <strong>Content Provider<\/strong>.<\/p>\n<p>Si tratta di componenti &#8211; alla pari di Service, Activity e Broadcast Receiver &#8211; che <strong>permettono di leggere e modificare dati presenti in una determinata sorgente, inviando chiamate ad un indirizzo univoco,\u00a0<\/strong>detto URI. I comandi passati rispecchiano le quattro operazioni CRUD eseguibili sui database (Create, Read, Update, Delete).<\/p>\n<p>I Content Provider vengono utilizzati in vari ambiti:<\/p>\n<ul>\n<li>per condividere basi di dati\u00a0di utilit\u00e0 generale presenti nel sistema operativo: si pensi ai Contatti, al dizionario utente, al Calendario e molto altro;<\/li>\n<li>per fare in modo che pi\u00f9 applicazioni possano condividere gli stessi dati, cosa che capita spesso quando pi\u00f9 app provengono dallo stesso produttore;<\/li>\n<li>come elemento architetturale interno ad un&#8217;app articolata in cui pi\u00f9 componenti accedono agli stessi dati.<\/li>\n<\/ul>\n<p>In questo post, prenderemo contatto con i concetti fondamentali di questo strumento e li sperimenteremo interrogando un Content Provider messo a disposizione da\u00a0Android che rappresenta la sorgente dati delle Impostazioni di sistema.<\/p>\n<h2>Accesso ai dati: ContentResolver e URI<\/h2>\n<p>L&#8217;<strong>accesso ad un ContentProvider non differisce molto da quello ad un comune database Sqlite<\/strong>: accederemo alle risorse con metodi omonimi a quelli utilizzati nella classe <em>SqliteDatabase<\/em> e, per le query, otterremo come risultato un <em>Cursor<\/em> che potremo legare ad un&#8217;interfaccia utente con un <em>CursorAdapter<\/em>.<\/p>\n<p>L&#8217;oggetto che permette di invocare un ContentProvider \u00e8 il <strong>ContentResolver<\/strong> di cui otterremo un riferimento dal <em>Context<\/em> tramite il metodo <em>getContentResolver<\/em>. L&#8217;indirizzo che permetter\u00e0 di identificare univocamente il Content Provider al quale siamo interessati \u00e8 rappresentato da un <strong>URI<\/strong> che, nelle invocazioni, svolger\u00e0 un ruolo simile a quello svolto dal nome della tabella da leggere o modificare nell&#8217;utilizzo dei database.<\/p>\n<p><strong>Per ogni Content Provider possono esistere pi\u00f9 URI<\/strong> che indicheranno risorse diverse: chi ha esperienza di backend web\u00a0trover\u00e0 molte affinit\u00e0 tra Content Provider e API REST per l&#8217;accesso ai dati.<\/p>\n<h2>Esempio: accedere alle Impostazioni di sistema<\/h2>\n<p>In Android, le Impostazioni di sistema vengono offerte come Content Provider. In casi come questo, dove si tratta di informazioni molto utili, si d\u00e0 la possibilit\u00e0 di accedervi inviando delle richieste all&#8217;URI tramite <em>ContentResolver<\/em> o, in alternativa, mettendo a disposizione dei metodi di utilit\u00e0. <strong>Le Impostazioni di sistema sono essenzialmente propriet\u00e0 costituite da coppie chiave\/valore<\/strong>: una stringa rappresenta la chiave (il nome della propriet\u00e0), un&#8217;altra stringa o un numero (intero o con virgola) ne rappresenta il valore. Pertanto esistono metodi come <em>getInt(ContentResolver cr, String name)<\/em> che legger\u00e0 una propriet\u00e0 con valore\u00a0Integer di cui forniremo il nome ed il <em>ContentResolver<\/em> relativo al nostro <em>Context<\/em> oppure <em>putInt(ContentResolver cr, String name, int value)<\/em> con cui assegneremo il valore <em>value<\/em> alla propriet\u00e0 di nome <em>name<\/em>: la presenza del ContentResolver rivela l&#8217;utilizzo di un ContentProvider.<\/p>\n<p>Noi, per\u00f2, in questo esempio eviteremo di utilizzare metodi di comodit\u00e0 facendo accesso direttamente al Content Provider: il nostro scopo sar\u00e0 quello di ottenere una lista delle propriet\u00e0 di sistema del dispositivo.<\/p>\n<p>Tutto il codice che usiamo \u00e8 inserito nel metodo <em>onCreate<\/em> dell&#8217;Activity. Per compattezza non useremo nemmeno un file esterno per il layout ma una ListView istanziata direttamente come oggetto:<\/p>\n<pre class=\"lang:java decode:true\">public class MainActivity extends AppCompatActivity {\r\n\r\n    @Override\r\n    protected void onCreate(Bundle savedInstanceState) {\r\n        super.onCreate(savedInstanceState);\r\n\r\n        \/\/ creiamo una ListView che diventa il layout dell'app\r\n        ListView lv=new ListView(this);\r\n        setContentView(lv);\r\n\r\n        \/\/ leggiamo dal ContentProvider la lista\r\n        \/\/ delle propriet\u00e0 di sistema con relativi valori\r\n        Cursor crs=getContentResolver().query(\r\n                Settings.System.CONTENT_URI,\r\n                null,\r\n                null,\r\n                null,\r\n                null\r\n\r\n        );\r\n\r\n        \/\/ usiamo un normale SimpleCursorAdapter per leggere il Cursor\r\n        SimpleCursorAdapter adapter=new SimpleCursorAdapter(\r\n                this,\r\n                android.R.layout.simple_list_item_2,\r\n                crs,\r\n                new String[]{\"name\", \"value\"},\r\n                new int[]{android.R.id.text1,android.R.id.text2},\r\n                0\r\n        );\r\n\r\n        \/\/ leghiamo il CursorAdapter alla ListView\r\n        lv.setAdapter(adapter);\r\n    }\r\n}<\/pre>\n<p>Per chi \u00e8 abituato ad utilizzare i database Sqlite in Android, il codice appare molto familiare, l&#8217;unico vero punto di novit\u00e0 \u00e8 la riga:<\/p>\n<pre class=\"lang:java decode:true \">Cursor crs=getContentResolver().query(\r\n                Settings.System.CONTENT_URI,\r\n                null,\r\n                null,\r\n                null,\r\n                null\r\n\r\n        );<\/pre>\n<p>dove effettuiamo una query, ottenendo un <em>Cursor<\/em>, ma inoltrandola tramite <em>ContentResolver<\/em>. Anche l&#8217;URI sar\u00e0 ottenuto da una classe del SDK, essendo una costante di Settings.System. I parametri successivi impostati a <em>null<\/em> occuperanno il posto riservato, rispettivamente,\u00a0ad un array di String che funger\u00e0 da proiezione, una stringa ed un altro array di String che insieme costituiranno il corpo della clausola WHERE (nello stile parametrico di SqliteDatabase) ed un ulteriore oggetto String che fornir\u00e0 le impostazioni della clausola ORDER BY.<\/p>\n<p>Il risultato apparir\u00e0 cos\u00ec:<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12880\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_01.png\" alt=\"\" width=\"367\" height=\"518\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_01.png 367w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_01-213x300.png 213w\" sizes=\"auto, (max-width: 367px) 100vw, 367px\" \/><\/a><\/p>\n<p>Ogni riga fornisce una propriet\u00e0 (registrata tra le costanti disponibili nella classe Settings.System) ed il valore.<\/p>\n<p>Osserviamo da vicino una propriet\u00e0 a titolo di esempio. Questo \u00e8 ci\u00f2 che appare a proposito della lingua impostata nel dispositivo (l&#8217;emulatore \u00e8 in italiano):<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_02.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12881\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_02.png\" alt=\"\" width=\"368\" height=\"392\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_02.png 368w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_02-282x300.png 282w\" sizes=\"auto, (max-width: 368px) 100vw, 368px\" \/><\/a><\/p>\n<p>Apriamo l&#8217;app per le Impostazioni di sistema e andiamo a scegliere una seconda lingua (sistema operativo Android 7.0). Prendiamo ad esempio l&#8217;inglese:<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_03.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12882\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_03.png\" alt=\"\" width=\"379\" height=\"327\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_03.png 379w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_03-300x259.png 300w\" sizes=\"auto, (max-width: 379px) 100vw, 379px\" \/><\/a><\/p>\n<p>Ricarichiamo l&#8217;app e verifichiamo se la modifica \u00e8 stata apportata:<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_04.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12883\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_04.png\" alt=\"\" width=\"370\" height=\"324\" srcset=\"https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_04.png 370w, https:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2017\/02\/content-provider-introduzione-alla-condivisione-di-dati-in-android_img_04-300x263.png 300w\" sizes=\"auto, (max-width: 370px) 100vw, 370px\" \/><\/a><\/p>\n<p>Come possiamo vedere, il valore \u00e8 gi\u00e0 cambiato ed, in particolare, rileva la scelta della lingua inglese.<\/p>\n<h2>Conclusioni<\/h2>\n<p>Quanto abbiamo visto \u00e8 solo un&#8217;introduzione all&#8217;argomento corredata da una rapida dimostrazione ma per sperimentare le potenzialit\u00e0 dei Content Provider e comprendere perch\u00e9 essi costituiscano una pietra miliare dell&#8217;ecosistema Android il nostro discorso dovr\u00e0 necessariamente andare avanti.<\/p>\n<p>Nei prossimi articoli vedremo come poter modificare i dati offerti da importanti Content Provider di sistema e, soprattutto, come mettere in condivisione dati creando componenti di questo tipo nei nostri progetti.<\/p>\n<p>A presto!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Tutte le applicazioni Android devono avere cura dei dati che gestiscono, in qualunque maniera siano immagazzinati. Considerando&#8230;<\/p>\n","protected":false},"author":561,"featured_media":13014,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1682,1],"tags":[1278,1898,1530,1697],"class_list":["post-12874","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-tutorial-pratici","tag-android","tag-content-provider","tag-database","tag-database-sqlite"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/12874","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=12874"}],"version-history":[{"count":5,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/12874\/revisions"}],"predecessor-version":[{"id":12884,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/12874\/revisions\/12884"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media\/13014"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=12874"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=12874"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=12874"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}