I fornitori di contenuti Android sono un modo semplice per gestire ed esporre i dati da un'applicazione, soprattutto se supportati da un database. In questo tutorial vedrai un modo rapido per fornire un'implementazione specifica e rapida di un database e di un fornitore di contenuti.
In questa continuazione dell'ultimo tutorial, Android Barometer Logger: Acquisizione dei dati del sensore, implementeremo il codice per la lettura regolare dei dati del sensore barometrico e lo memorizzeremo in modo persistente. Imparerai a leggere i dati del sensore e come pianificare gli eventi ricorrenti in modo che l'applicazione e il relativo servizio non debbano rimanere in esecuzione.
Questo tutorial presume che tu abbia una conoscenza di base di Android e Java, che tu abbia tutti gli strumenti Android installati e funzionanti e che tu ti sia comodo con il caricamento e il test delle applicazioni su un dispositivo Android. Useremo il sensore hardware del barometro in questa applicazione. Se non si dispone di un dispositivo con questo sensore, è possibile sostituirlo con un altro sensore simile, a scopo di test, ma i risultati o l'utilità potrebbero non essere equivalenti.
Potresti aver visto database e fornitori di contenuti comparsi in altri tutorial; questo presenta una variante veloce e "sporca" per l'hobbista o l'appassionato che desidera registrare rapidamente alcuni dati in un database strutturato e visualizzarli più tardi in un modo facile per Android..
Il modo più veloce per creare un database su Android utilizzando SQLite è utilizzare la classe SQLiteOpenHelper. I record di dati che desideriamo registrare sono di struttura molto semplice: un timestamp e un valore che rappresenta la pressione in quel momento.
Lo schema per questo database è semplice. Oltre alle due colonne di dati obbligatori per il timestamp e il valore di pressione, creeremo anche un identificatore univoco, utile se dovessimo mai espandere lo schema o se fosse necessario trattare i dati in base a una singola riga di dati. Ecco la definizione dello schema per la classe SQLiteOpenHelper:
static final String TABLE_NAME = "table_sensor_data"; stringa finale statica COL_ID = "_id"; stringa finale statica COL_VALUE = "valore"; stringa finale statica COL_TIMESTAMP = "timestamp"; private static final String DB_SCHEMA = "CREATE TABLE" + TABLE_NAME + "(" + COL_ID + "INTEGER PRIMARY KEY AUTOINCREMENT," + COL_TIMESTAMP + "INTEGER NOT NULL," + COL_VALUE + "REAL" + ");";
SQLite può effettivamente memorizzare timestamp in molti modi e manipolarli internamente. Tuttavia, potremmo non aver mai bisogno di manipolarli, quindi possiamo semplicemente memorizzare il valore letto dal sensore.
Con lo schema fuori mano, il resto di SQLiteOpenHelperclass è banale:
public class SensorDataHelper estende SQLiteOpenHelper String statico finale privata DEBUG_TAG = "SensorDataHelper"; stringa finale statica privata DATABASE_NAME = "sensor_data.db"; private static final int DATABASE_VERSION = 1; // schema // .... SensorDataHelper (Context context) super (context, DATABASE_NAME, null, DATABASE_VERSION); @Override public void onCreate (SQLiteDatabase db) db.execSQL (DB_SCHEMA); @Override public void onUpgrade (SQLiteDatabase db, int oldVersion, int newVersion) Log.w (DEBUG_TAG, "Avviso: eliminazione di tutte le tabelle, migrazione dei dati non supportata"); db.execSQL ("DROP TABLE IF EXISTS" + TABLE_NAME); onCreate (db);
Fondamentalmente, configuriamo la versione del database e decidiamo come gestire le modifiche e gli aggiornamenti della versione - in questo caso, rilasciamo tutti i dati su un aggiornamento. Non supportiamo la migrazione dei dati. Tuttavia, è possibile aggiungere facilmente il codice qui per migrare i dati su un aggiornamento, se necessario.
I fornitori di contenuti sono il modo di Android di esporre i dati strutturati tramite i cursori proteggendo al tempo stesso i dati sottostanti. I dati dell'applicazione vengono interrogati tramite il provider di contenuti anziché accedere direttamente dal database dell'applicazione. Poiché questa implementazione utilizza SQLiteOpenHelper, l'attività di creazione di un provider di contenuti è semplice.
Mentre un fornitore di contenuti completamente funzionale che gestisce tutte le operazioni di dati come le query, gli inserimenti, gli aggiornamenti e le eliminazioni richiede poco più lavoro di uno parziale, per scopi di registrazione tutto ciò di cui abbiamo veramente bisogno per l'implementazione è il metodo insert (). Ottenere i dati richiede l'implementazione del metodo query (), che sfrutterà anche la classe helper di URIMatcher. Puoi sempre tornare indietro e implementare altre funzionalità del fornitore di contenuti in un secondo momento, in caso di modifica delle tue esigenze. La maggior parte della registrazione dei dati, tuttavia, richiede record completi e inalterati.
Implementiamo un fornitore di contenuti che funzioni con i nostri piani di registrazione dei sensori. Innanzitutto, imposta alcune costanti utili e l'URIMatcher per aiutarci a confrontare gli URI con il tipo di dati che rappresentano:
public class SensorDataProvider estende ContentProvider string statico finale privato DEBUG_TAG = "TutListProvider"; sensorDataHelper sensorDataHelper privato; public static final int SENSORDATA = 100; public static final int SENSORDATA_ID = 110; private static final String AUTHORITY = "com.mamlambo.barologger.SensorDataProvider"; stringa statica finale privata BASE_PATH = "sensordata"; pubblico statico finale Uri CONTENT_URI = Uri.parse ("content: //" + AUTHORITY + "/" + BASE_PATH); stringa finale statica pubblica CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + "/ barolog"; stringa statica finale pubblica CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/ barolog"; finale statico privato UriMatcher sURIMatcher = nuovo UriMatcher (UriMatcher.NO_MATCH); static sURIMatcher.addURI (AUTHORITY, BASE_PATH, SENSORDATA); sURIMatcher.addURI (AUTHORITY, BASE_PATH + "/ #", SENSORDATA_ID); // ... [codice sorgente] Un consumatore di questo fornitore di contenuti farà riferimento al valore CONTENT_URI. L'AUTORITÀ viene utilizzata dalla voce del provider nel file manifest.
Passaggio 3: Inserimento e domanda di implementazione
I metodi insert () e query () sono implementati utilizzando un semplice mapping ai metodi helper dagli oggetti del database SQLite. [sourcecode language = "java"] @Override public Uri insert (Uri uri, ContentValues values) int uriType = sURIMatcher.match (uri); if (uriType! = SENSORDATA) throw new IllegalArgumentException ("URI non valido per l'inserimento"); SQLiteDatabase sqlDB = getDatabase (true); prova 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 throw new SQLException ("Impossibile inserire row in" + uri); catch (SQLiteConstraintException e) Log.w (DEBUG_TAG, "Warning: Ignoring constraint failure."); return null;
La maggior parte di ciò che vedi qui è la gestione degli errori. La chiamata principale, insertOrThrow (), utilizza i dati direttamente dai parametri al metodo insert ().
E ora il metodo query ():
@Override query Cursore pubblico (Uri uri, String [] proiezione, Selezione stringa, 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 ()); rompere; caso SENSORDATA: // nessun filtro interrotto; default: lanciare IllegalArgumentException ("URI sconosciuto"); Cursore cursor = queryBuilder.query (getDatabase (false), proiezione, selezione, selectionArgs, null, null, sortOrder); cursor.setNotificationUri (getContext (). getContentResolver (), uri); ritorno cursore;
L'unica modifica al metodo query () è l'aggiunta dell'identificatore alla clausola where se l'URI contiene un percorso per un record specifico. Altrimenti, anche i parametri del metodo query () vengono passati così come sono alla chiamata al metodo query (). Molto conveniente.
Abbiamo utilizzato un metodo di supporto per ottenere l'istanza dell'oggetto SQLiteDatabase. In questo modo creiamo solo l'oggetto SQLiteOpenHelper quando assolutamente necessario. Questo è raccomandato per migliorare le prestazioni generali.
SQLiteDatabase privato getDatabase (booleano scrivibile) if (sensorDataHelper == null) sensorDataHelper = new SensorDataHelper (getContext ()); return (scrivibile? sensorDataHelper.getWritableDatabase (): sensorDataHelper.getReadableDatabase ());
Infine, un fornitore di contenuti deve essere registrato come fornitore nel file manifest dell'applicazione
[codice sorgente] Il campo nome è il nome della classe del fornitore di contenuti e l'autorizzazione deve corrispondere all'autorità utilizzata nel provider di contenuti.
Parte C: inserimento dei dati
Ritornando all'AsyncTask del Servizio implementato nell'ultimo tutorial, ora è necessario inserire effettivamente i dati nel fornitore di contenuti man mano che vengono acquisite nuove letture del sensore. La semplicità di questo processo potrebbe sorprenderti: [sourcecode language = "java"] ContentValues values = new ContentValues (); values.put (SensorDataHelper.COL_VALUE, value); values.put (SensorDataHelper.COL_TIMESTAMP, timestamp); getContentResolver (). insert (SensorDataProvider.CONTENT_URI, values);
Questa semplicità è una delle ragioni per cui ci piace il sovraccarico marginale dell'implementazione di un fornitore di contenuti su un database.
In questo tutorial, hai imparato come creare rapidamente un semplice database applicativo e il relativo fornitore di contenuti e utilizzarlo per registrare facilmente i dati - in questo caso le letture della pressione atmosferica prelevate dal dispositivo a intervalli regolari.
Come sfida, implementa questo codice da solo. Completare l'implementazione del fornitore di contenuti implementando i metodi delete () e update (). Sono necessari per il tuo logger? Possono essere usati per mettere in atto l'integrità dei dati?
Gli sviluppatori mobili Lauren Darcey e Shane Conder hanno coautore diversi libri sullo sviluppo di Android: un libro di programmazione approfondito intitolato Sviluppo di applicazioni wireless Android (ora nella sua terza edizione come set di due volumi) e Sams ti insegna a sviluppare applicazioni Android in 24 ore. Quando non scrivono, passano il loro tempo a sviluppare software mobile presso la loro azienda ea fornire servizi di consulenza. Possono essere contattati via email a [email protected], tramite il loro blog su androidbook.blogspot.com e su Twitter @androidwireless.