Android Barometer Logger opname van sensorgegevens

Aanbieders van Android-inhoud zijn een eenvoudige manier om gegevens van een toepassing te beheren en te ontmaskeren, vooral wanneer deze worden ondersteund door een database. In deze zelfstudie ziet u een snelle manier om een ​​specifieke, snelle implementatie van zowel een database als een inhoudsprovider te bieden.

In deze voortzetting van de laatste zelfstudie, Android Barometer Logger: Sensorgegevens verkrijgen, zullen we code implementeren om barometrische sensorgegevens regelmatig te lezen en op een persistente manier op te slaan. U leert de sensorgegevens te lezen en herhaalde gebeurtenissen zo in te plannen dat de toepassing en de bijbehorende service niet hoeven te blijven werken.


Ermee beginnen

Deze tutorial gaat ervan uit dat je een basiskennis hebt van Android en Java, dat je alle Android-tools hebt geïnstalleerd en werkt en dat je vertrouwd bent met het laden en testen van applicaties op een Android-apparaat. We gebruiken de barometer-hardwaresensor in deze toepassing. Als u geen apparaat met deze sensor hebt, kunt u dit vervangen voor een andere, vergelijkbare sensor, maar de resultaten of bruikbaarheid zijn mogelijk niet hetzelfde.

Mogelijk hebt u in een aantal zelfstudies databases en inhoudsproviders te zien gekregen; deze presenteert een snelle, "snel-en-vieze" variant voor de hobbyist of liefhebber die snel enkele gegevens in een gestructureerde database wil loggen en later gemakkelijk wil weergeven, allemaal op een Android-vriendelijke manier.


Deel A: Een database maken

De snelste manier om een ​​database op Android te maken met SQLite is om de SQLiteOpenHelper-klasse te gebruiken. De gegevensrecords die we willen loggen hebben een zeer eenvoudige structuur: een tijdstempel en een waarde die de druk op dat moment weergeeft.


Stap 1: Het schema bepalen

Het schema voor deze database is eenvoudig. Naast de twee vereiste gegevenskolommen voor het tijdstempel en de drukwaarde, maken we ook een uniek ID - handig moeten we het schema uitbreiden of de gegevens rij per rij verwerken. Dit is de schemadefinitie voor de SQLiteOpenHelper-klasse:

 statische finale String TABLE_NAME = "table_sensor_data"; static final String COL_ID = "_id"; static final String COL_VALUE = "waarde"; static final String COL_TIMESTAMP = "timestamp"; private static final String DB_SCHEMA = "MAAK TABLE" + TABLE_NAME + "(" + COL_ID + "INTEGER PRIMARY KEY AUTOINCREMENT," + COL_TIMESTAMP + "INTEGER NOT NULL," + COL_VALUE + "REAL" + ");";

SQLite kan tijdstempels op verschillende manieren opslaan en intern manipuleren. Het is echter mogelijk dat we ze nooit hoeven te manipuleren, dus we kunnen gewoon de waarde opslaan die van de sensor is gelezen.


Stap 2: Implementatie van de SQLiteOpenHelper-klasse

Met het schema uit de weg, de rest van de SQLiteOpenHelperclass is triviaal:

 public class SensorDataHelper breidt SQLiteOpenHelper uit private static final String DEBUG_TAG = "SensorDataHelper"; private static final String 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, "Waarschuwing: alle tabellen laten vallen; gegevensmigratie niet ondersteund"); db.execSQL ("DROP-TABEL ALS BESTAAT" + TABLE_NAME); onCreate (db); 

Kortom, we configureren de databaseversie en bepalen hoe we omgaan met versieveranderingen en upgrades - in dit geval laten we alle gegevens achter bij een upgrade. We ondersteunen geen gegevensmigratie. U kunt hier echter eenvoudig code toevoegen om indien nodig gegevens over een upgrade te migreren.


Deel B: Implementatie van een eenvoudige content provider

Contentproviders zijn de manier van Android om gestructureerde gegevens via Cursors bloot te leggen en tegelijkertijd de onderliggende gegevens te beschermen. Applicatiegegevens worden opgevraagd via de contentprovider in plaats van rechtstreeks vanuit de toepassingsdatabase te worden benaderd. Omdat deze implementatie een SQLiteOpenHelper gebruikt, is de taak van het maken van een contentprovider eenvoudig.


Stap 1: kiezen wat te implementeren

Hoewel een volledig functionele contentprovider die alle gegevensbewerkingen zoals query's, invoegingen, updates en verwijderingen afhandelt, weinig meer werk dan een gedeeltelijke bewerking vereist, is voor logboekdoeleinden alles wat we echt nodig hebben voor een invoerprogramma de methode insert (). Voor gegevensuitwisseling is de implementatie van de methode query () vereist, die ook gebruikmaakt van de URIMatcher-helperklasse. U kunt later altijd teruggaan en later andere functies van de contentprovider implementeren als uw vereisten veranderen. Voor de meeste gegevensregistraties zijn echter complete, niet-gewijzigde records vereist.


Stap 2: Implementatie details

Laten we een contentprovider implementeren die werkt met onze sensorregistratieplannen. Stel eerst enkele bruikbare constanten en de URIMatcher in om ons te helpen de URI's te koppelen aan het type gegevens dat ze vertegenwoordigen:

 public class SensorDataProvider breidt ContentProvider uit private static final String DEBUG_TAG = "TutListProvider"; privé SensorDataHelper sensorDataHelper; openbare statische uiteindelijke 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"; private static final UriMatcher sURIMatcher = nieuwe UriMatcher (UriMatcher.NO_MATCH); static sURIMatcher.addURI (AUTORITEIT, BASE_PATH, SENSORDATA); sURIMatcher.addURI (AUTHORITY, BASE_PATH + "/ #", SENSORDATA_ID);  // ... [broncode] Een consument van deze inhoudsprovider verwijst naar de waarde CONTENT_URI. De AUTORITEIT wordt gebruikt door de provider-vermelding in het manifestbestand. 

Stap 3: Implementatie invoegen en opvragen

De methoden insert () en query () worden geïmplementeerd met behulp van eenvoudige toewijzingsmethoden voor hulp van de SQLite-databaseobjecten. [sourcecode language = "java"] @Override public Uri insert (Uri uri, ContentValues ​​values) int uriType = sURIMatcher.match (uri); if (uriType! = SENSORDATA) gooi nieuwe IllegalArgumentException ("Ongeldige URI voor invoegen"); SQLiteDatabase sqlDB = getDatabase (waar); probeer long newID = sqlDB.insertOrThrow (SensorDataHelper.TABLE_NAME, null, values); if (newID> 0) Uri newUri = ContentUris.withAppendedId (uri, newID); getContext (). getContentResolver (). notifyChange (uri, null); nieuweUri teruggeven; else gooi nieuwe SQLException ("Misplaatst rij invoegen in" + uri); catch (SQLiteConstraintException e) Log.w (DEBUG_TAG, "Waarschuwing: negeren van constraint failure."); return null;

Het meeste van wat je hier ziet, is foutafhandeling. De hoofdoproep, insertOrThrow (), gebruikt gegevens rechtstreeks van de parameters in de methode insert ().

En nu de methode query ():

 @Override openbare Cursor-query (Uri-uri, String [] -projectie, String-selectie, 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 ()); breken; case SENSORDATA: // geen filterbreuk; standaard: gooi nieuwe IllegalArgumentException ("Onbekende URI");  Cursor cursor = queryBuilder.query (getDatabase (false), projectie, selectie, selectionArgs, null, null, sortOrder); cursor.setNotificationUri (getContext (). getContentResolver (), uri); return cursor; 

De enige wijziging in de methode query () is het toevoegen van de identifier aan de where-component als de URI een pad naar een specifieke record bevat. Anders worden de parameters van de query () -methode ook doorgegeven aan de methode request (). Erg handig.

We hebben een hulpmethode gebruikt om het object SQLiteDatabase-object te verkrijgen. Dit is zodat we alleen het SQLiteOpenHelper-object maken wanneer dit absoluut noodzakelijk is. Dit wordt aanbevolen om de algehele prestaties te verbeteren.

 private SQLiteDatabase getDatabase (boolean writable) if (sensorDataHelper == null) sensorDataHelper = nieuwe SensorDataHelper (getContext ());  return (beschrijfbaar? sensorDataHelper.getWritableDatabase (): sensorDataHelper.getReadableDatabase ()); 

Stap 3: Het manifest bijwerken

Ten slotte moet een inhoudsprovider als een provider worden geregistreerd in het manifestbestand van de toepassing in de tag, zoals zo:

   [sourcecode] Het veld naam is de klassenaam van de contentprovider en de autoriteit moet overeenkomen met de autoriteit die wordt gebruikt in uw contentprovider. 

Deel C: gegevens invoegen

Terug in het AsyncTask van de Service die we in de laatste zelfstudie hebben geïmplementeerd, moeten we nu de gegevens daadwerkelijk in de contentprovider invoegen wanneer nieuwe sensormetingen worden gemaakt. De eenvoud van dit proces kan je verbazen: [sourcecode language = "java"] ContentValues ​​values ​​= nieuwe ContentValues ​​(); values.put (SensorDataHelper.COL_VALUE, waarde); values.put (SensorDataHelper.COL_TIMESTAMP, timestamp); getContentResolver (). insert (SensorDataProvider.CONTENT_URI, waarden);

Deze eenvoud is een reden waarom we de marginale overhead van het implementeren van een contentprovider bovenop een database waarderen.


Conclusie

In deze zelfstudie hebt u geleerd hoe u snel een eenvoudige toepassingsdatabase en aanverwante contentprovider kunt maken en deze kunt gebruiken om eenvoudig gegevens te loggen - in dit geval de barometerdrukmetingen die met regelmatige tussenpozen uit het apparaat worden genomen.

Als een uitdaging, implementeer deze code alleen. Rond de implementatie van de contentprovider af door de methoden delete () en update () te implementeren. Zijn ze nodig voor uw logger? Kan weglaten ze worden gebruikt om gegevensintegriteit af te dwingen?


Over de Auteurs

Mobiele ontwikkelaars Lauren Darcey en Shane Conder hebben samen meerdere boeken geschreven over Android-ontwikkeling: een diepgaand programmeerboek getiteld Android Wireless Application Development (nu in zijn derde editie als set met twee volumes) en Sams Teach Yourself Android Application Development in 24 uur. Wanneer ze niet schrijven, besteden ze hun tijd aan het ontwikkelen van mobiele software bij hun bedrijf en het leveren van consultingservices. Ze zijn te bereiken via e-mail naar [email protected], via hun blog op androidbook.blogspot.com, en op Twitter @androidwireless.

Meer hulp nodig bij het schrijven van Android-apps? Bekijk onze nieuwste boeken en bronnen!