Les fournisseurs de contenu Android constituent un moyen simple de gérer et d'exposer les données d'une application, en particulier lorsqu'elles sont sauvegardées par une base de données. Vous verrez un moyen rapide de fournir une implémentation spécifique et rapide d'une base de données et d'un fournisseur de contenu dans ce tutoriel..
Dans cette suite du dernier tutoriel, Android Barometer Logger: Acquisition de données de capteurs, nous allons implémenter un code permettant de lire régulièrement les données de capteurs barométriques et de les stocker de manière persistante. Vous apprendrez à lire les données du capteur et à planifier des événements récurrents pour que l'application et son service ne restent pas en cours d'exécution..
Ce didacticiel suppose que vous maîtrisiez bien Android et Java, que tous les outils Android étaient installés et fonctionnaient et que vous maîtrisiez bien le chargement et le test d'applications sur un appareil Android. Nous utiliserons le capteur matériel du baromètre dans cette application. Si vous n'avez pas d'appareil avec ce capteur, vous pouvez le remplacer par un autre capteur similaire à des fins de test, mais les résultats ou l'utilité peuvent ne pas être équivalents..
Vous avez peut-être déjà vu des fournisseurs de base de données et de contenu apparaître dans d'autres didacticiels; Celui-ci présente une variante rapide, "rapide et sale" pour les amateurs ou les passionnés souhaitant enregistrer rapidement des données dans une base de données structurée et les afficher facilement plus tard, le tout de manière conviviale sur Android.
Le moyen le plus rapide de créer une base de données sur Android à l'aide de SQLite consiste à utiliser la classe SQLiteOpenHelper. Les enregistrements de données que nous souhaitons consigner ont une structure très simple: un horodatage et une valeur représentant la pression à ce moment-là..
Le schéma pour cette base de données est simple. Au-delà des deux colonnes de données requises pour l'horodatage et la valeur de pression, nous allons également créer un identifiant unique - utile si vous développez jamais le schéma ou si vous devez traiter les données ligne par ligne. Voici la définition du schéma pour la classe SQLiteOpenHelper:
static final String TABLE_NAME = "table_sensor_data"; static final String COL_ID = "_id"; static final String COL_VALUE = "valeur"; static final String COL_TIMESTAMP = "horodatage"; private static final String DB_SCHEMA = "CREATE TABLE" + TABLE_NAME + "(" + COL_ID + "INTEGER PRIMARY KEY AUTOINCREMENT," + COL_TIMESTAMP + "INTEGER NON NULL," + COL_VALUE + "REAL" + ");";
SQLite peut en réalité stocker les horodatages de nombreuses manières et les manipuler en interne. Cependant, nous n’aurons peut-être jamais besoin de les manipuler, nous ne pouvons donc enregistrer que la valeur lue par le capteur..
Avec le schéma en place, le reste de la classe SQLiteOpenHelper est trivial:
Classe publique SensorDataHelper étend SQLiteOpenHelper private statique final String DEBUG_TAG = "SensorDataHelper"; private static final String DATABASE_NAME = "sensor_data.db"; private final final int DATABASE_VERSION = 1; // schéma //…. SensorDataHelper (contexte de contexte) super (contexte, DATABASE_NAME, null, DATABASE_VERSION); @Override public void onCreate (base de données SQLiteDatabase) db.execSQL (DB_SCHEMA); @Override public void onUpgrade (base de données SQLiteDat, int oldVersion, int newVersion) Log.w (DEBUG_TAG, "Avertissement: suppression de toutes les tables; migration de données non prise en charge"); db.execSQL ("DROP TABLE IF EXISTS" + TABLE_NAME); onCreate (db);
Fondamentalement, nous configurons la version de la base de données et décidons comment nous voulons gérer les modifications et les mises à niveau de version. Dans ce cas, nous supprimons toutes les données lors d'une mise à niveau. Nous ne prenons pas en charge la migration de données. Cependant, vous pouvez facilement ajouter du code ici pour migrer les données sur une mise à niveau si nécessaire..
Les fournisseurs de contenu sont le moyen utilisé par Android pour exposer des données structurées via des curseurs tout en protégeant les données sous-jacentes. Les données d'application sont interrogées via le fournisseur de contenu au lieu d'être directement accessibles depuis la base de données d'application. Comme cette implémentation utilise SQLiteOpenHelper, la création d'un fournisseur de contenu est une tâche simple..
Bien qu'un fournisseur de contenu entièrement fonctionnel qui gère toutes les opérations de données, telles que les requêtes, les insertions, les mises à jour et les suppressions, demande un peu plus de travail qu'un travail partiel, pour la journalisation, tout ce dont nous avons besoin pour implémenter l'entrée est la méthode insert (). Obtenir des données nécessite la mise en œuvre de la méthode query (), qui utilisera également la classe d'assistance URIMatcher. Vous pouvez toujours revenir en arrière et implémenter d'autres fonctionnalités du fournisseur de contenu ultérieurement, si vos exigences changent. La plupart des enregistrements de données, cependant, nécessitent des enregistrements complets et non modifiés..
Implémentons un fournisseur de contenu qui fonctionne avec nos plans de journalisation de capteurs. Tout d’abord, configurez quelques constantes utiles et URIMatcher pour nous aider à faire correspondre les URI au type de données qu’ils représentent:
Classe publique SensorDataProvider étend ContentProvider private static final String DEBUG_TAG = "TutListProvider"; private SensorDataHelper sensorDataHelper; public static final int SENSORDATA = 100; public static final int SENSORDATA_ID = 110; private static final String AUTHORITY = "com.mamlambo.barologger.SensorDataProvider"; private static final String BASE_PATH = "sensordata"; public static final Uri CONTENT_URI = Uri.parse ("content: //" + AUTHORITY + "/" + BASE_PATH); public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/ barolog"; public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/ barolog"; final statique privé UriMatcher sURIMatcher = new UriMatcher (UriMatcher.NO_MATCH); static sURIMatcher.addURI (AUTHORITY, BASE_PATH, SENSORDATA); sURIMatcher.addURI (AUTHORITY, BASE_PATH + "/ #", SENSORDATA_ID); //… [code source] Un consommateur de ce fournisseur de contenu fera référence à la valeur CONTENT_URI. L'AUTHORITÉ est utilisée par l'entrée du fournisseur dans le fichier manifeste.
Étape 3: Implémentation et requête d'implémentation
Les méthodes insert () et query () sont implémentées à l'aide d'un mappage simple des méthodes d'assistance à partir des objets de base de données SQLite. [sourcecode language = "java"] @Override public Uri insert (Uri uri, valeurs ContentValues) int uriType = sURIMatcher.match (uri); if (uriType! = SENSORDATA) lance la nouvelle IllegalArgumentException ("URI non valide pour l'insertion"); SQLiteDatabase sqlDB = getDatabase (true); try long newID = sqlDB.insertOrThrow (SensorDataHelper.TABLE_NAME, null, values); if (newID> 0) Uri newUri = ContentUris.withAppendedId (uri, newID); getContext (). getContentResolver (). notifyChange (uri, null); return newUri; else jeter un nouveau SQLException ("Impossible d'insérer une ligne dans" + uri); catch (SQLiteConstraintException e) Log.w (DEBUG_TAG, "Avertissement: échec de la contrainte."); return null;
La plupart de ce que vous voyez ici est la gestion des erreurs. L'appel principal, insertOrThrow (), utilise les données directement des paramètres de la méthode insert ()..
Et maintenant, la méthode query ():
@Override public Requête de curseur (Uri uri, projection de String [], sélection de String, string [] selectionArgs, String sortOrder) SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder (); queryBuilder.setTables (SensorDataHelper.TABLE_NAME); int uriType = sURIMatcher.match (uri); switch (uriType) case SENSORDATA_ID: queryBuilder.appendWhere (SensorDataHelper.COL_ID + "=" + uri.getLastPathSegment ()); Pause; case SENSORDATA: // pas de rupture de filtre; défaut: lancer la nouvelle IllegalArgumentException ("Unknown URI"); Cursor cursor = queryBuilder.query (getDatabase (false), projection, sélection, selectionArgs, null, null, sortOrder); cursor.setNotificationUri (getContext (). getContentResolver (), uri); retourner le curseur;
La seule modification apportée à la méthode query () consiste à ajouter l'identificateur à la clause where si l'URI contient un chemin d'accès à un enregistrement spécifique. Sinon, les paramètres de la méthode query () sont également transmis tels quels à l'appel à la méthode query (). Très pratique.
Nous avons utilisé une méthode d'assistance pour obtenir l'instance d'objet SQLiteDatabase. C'est ainsi que nous créons l'objet SQLiteOpenHelper uniquement lorsque cela est absolument nécessaire. Ceci est recommandé pour améliorer les performances globales.
private SQLiteDatabase getDatabase (booléen accessible en écriture) if (sensorDataHelper == null) sensorDataHelper = new SensorDataHelper (getContext ()); return (writeable? sensorDataHelper.getWritableDatabase (): sensorDataHelper.getReadableDatabase ());
Enfin, un fournisseur de contenu doit être enregistré en tant que fournisseur dans le fichier manifeste de l'application dans le répertoire.
[code source] Le champ du nom est le nom de la classe du fournisseur de contenu et l'autorité doit correspondre à l'autorité utilisée dans votre fournisseur de contenu..
Partie C: Insertion de données
De retour dans la tâche asynchrone du service que nous avons implémentée dans le dernier tutoriel, nous devons maintenant insérer les données dans le fournisseur de contenu à mesure que de nouvelles lectures de capteurs sont effectuées. La simplicité de ce processus peut vous surprendre: [code source code = "java"] valeurs ContentValues = new ContentValues (); values.put (SensorDataHelper.COL_VALUE, valeur); values.put (SensorDataHelper.COL_TIMESTAMP, horodatage); getContentResolver (). insert (SensorDataProvider.CONTENT_URI, valeurs);
Cette simplicité est l'une des raisons pour lesquelles nous aimons le surcoût marginal lié à la mise en œuvre d'un fournisseur de contenu au-dessus d'une base de données..
Dans ce didacticiel, vous avez appris à créer rapidement une base de données d'application simple et un fournisseur de contenu associé, et à s'en servir pour enregistrer facilement des données - dans ce cas, les lectures de pression barométrique relevées à intervalles réguliers sur l'appareil..
Comme défi, implémentez ce code vous-même. Complétez l'implémentation du fournisseur de contenu en implémentant les méthodes delete () et update (). Sont-ils nécessaires pour votre enregistreur? Peut-on les laisser être utilisés pour imposer l'intégrité des données?
Les développeurs mobiles Lauren Darcey et Shane Conder ont co-écrit plusieurs livres sur le développement Android: un livre de programmation en profondeur intitulé Développement d'applications sans fil Android (maintenant dans sa troisième édition en deux volumes) et Sams Teach Yourself Développement d'applications Android en 24 heures. Lorsqu'ils n'écrivent pas, ils passent leur temps à développer des logiciels mobiles dans leur entreprise et à fournir des services de conseil. Vous pouvez les contacter par courrier électronique à l'adresse [email protected], via leur blog à l'adresse androidbook.blogspot.com et sur Twitter @androidwireless..