Android Room Tutorial: Vereinfachung der Arbeit mit App-Daten

Informationen sind wahrscheinlich die wichtigste Ressource, der Nutzer bei Apps vertrauen. Für App-Entwickler geben diese Informationen Aufschluss darüber, wer der Benutzer ist, was uns in die Lage versetzt, eine gute Benutzererfahrung (UX) zu bieten. Durch die Anwendung von Geschäftsregeln auf diese Informationen definieren wir außerdem das Verhalten, das die App haben sollte. Diese Informationen können sensibel sein und die privaten Daten der Benutzer preisgeben, daher ist es sehr wichtig, dass wir sie richtig handhaben, um ihre Integrität, Privatsphäre und ordnungsgemäße Speicherung zu gewährleisten. In diesem Android Room-Tutorial zeigen wir Ihnen, wie Sie mit diesen Daten einfacher arbeiten und gleichzeitig ihre Integrität und Sicherheit gewährleisten können, indem Sie Room verwenden. Room ist Teil der Android Architecture Components.

Brauchen Sie Room?

Wenn wir über das Speichern von Informationen in einer persistenten Weise auf Android sprechen, ist die wichtigste und „einfachste“ Option die Verwendung von einfachem SQLite. Eine gute Datenbankimplementierung mit SQLite bedeutet jedoch, dass eine Menge Code erzeugt wird, der keinen wirklichen Nutzen bringt. Die Architektur, die darauf folgt, ist oft nicht so sauber und klar, wie sie sein könnte.

Sie könnten auch objektrelationales Mapping oder ORM verwenden, aber Sie müssen die Datenbank immer noch manuell definieren und erstellen, SQLiteOpenHelper unterklassifizieren und die Vertragsklassen erstellen.

Die Frage ist also: Gibt es eine Möglichkeit, diesen ganzen Prozess zu vereinfachen? Die Antwort lautet: Ja, Raum ist Ihre Lösung.

Ein genauerer Blick auf Room und seine Funktionsweise

Room ist eines der wichtigsten Werkzeuge in den Android-Architekturkomponenten. Es wurde auf der Google I/O 2016 vorgestellt und ist ein leistungsstarkes Tool zum Speichern und Bearbeiten von Informationen in Android-Apps. Es bietet eine sehr einfache Möglichkeit, mit Daten zu arbeiten und gewährleistet stets ihre Sicherheit und Integrität.

Room ist kein ORM, sondern eine ganze Bibliothek, die es uns ermöglicht, SQLite-Datenbanken einfacher zu erstellen und zu manipulieren. Mit Hilfe von Annotationen können wir unsere Datenbanken, Tabellen und Operationen definieren. Room übersetzt diese Annotationen automatisch in SQLite-Anweisungen/Abfragen, um die entsprechenden Operationen in der Datenbank-Engine durchzuführen.

Die drei Hauptkomponenten von Room sind:

– Entity: Repräsentiert eine Tabelle innerhalb der Room-Datenbank. Sie sollte mit @Entity annotiert werden.

– DAO: Eine Schnittstelle, die die Methoden zum Zugriff auf die Datenbank enthält. Es wird mit @Dao.

– Database annotiert: Repräsentiert die Datenbank. Es ist ein Objekt, das eine Verbindung zur SQLite-Datenbank hält, und alle Operationen werden über sie ausgeführt. Es ist mit @Database annotiert.

Die Raumarchitektur sieht wie folgt aus:

Android Room Architektur

Zu viel Gerede – schauen wir uns ein Beispiel an

Lassen Sie uns in dieses Android Room Tutorial eintauchen. Stellen Sie sich vor, dass wir eine App erstellen müssen, um Ihr Fitnessprogramm zu speichern. Wir werden vier Entitäten in unserer Datenbank haben, wie wir unten zeigen werden. Der gesamte Beispielcode ist in Kotlin geschrieben (wenn du Kotlin nicht kennst oder mehr darüber erfahren möchtest, lade ich dich ein, meinen Artikel darüber zu lesen).

Das erste, was wir tun müssen, ist unsere gradle-Datei zu aktualisieren. Sie sollte wie folgt aussehen:

apply plugin: 'com.android.application'apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'apply plugin: 'kotlin-kapt'android { //.. Omitted since it is not relevant for the example}dependencies { //... some dependencies were omitted due to they are not relevant for the example def room_version = "2.2.0-rc01" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" compile 'com.google.code.gson:gson:2.2.4' implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' implementation 'io.reactivex.rxjava2:rxjava:2.1.17'}

Lassen Sie uns die drei Hauptkomponenten von Room betrachten und analysieren: Entitäten, DAOs und Datenbank.

Entitäten

Für unser Beispiel werden wir vier Entitäten verwenden: Geschlecht, Übung, Routine und Auszubildender.

Geschlecht.kt

Stellt das Geschlecht des Auszubildenden dar

@Entitydata class Gender( @PrimaryKey(autoGenerate = true) val id: Int? = null, val name: String)

Was zu beachten ist:

– Alle Klassen, die eine Entität der Datenbank darstellen, müssen mit @Entity

– Mit der Annotation @PrimaryKey(autoGenerate = true) geben wir an, dass die id der Primärschlüssel der Entität ist und von der Datenbank-Engine automatisch generiert werden soll.

Übung.kt

Stellt eine Übung dar, die Teil einer Routine ist.

@Entitydata class Exercise( @PrimaryKey(autoGenerate = true) val exerciseId: Int, val name: String, val repetitions:Int, @ColumnInfo(name = "machine_name") val machineName: String, val liftedWeight: Int)

Was zu beachten ist:

– Standardmäßig verwendet Room die Feldnamen als Spaltennamen in der Datenbank. Wenn eine Spalte einen anderen Namen haben soll, fügen Sie die @ColumnInfo-Annotation zu einem Feld hinzu.

Routine.kt

Grundsätzlich ein Container mit Übungen, die zusammen eine Übungsroutine bilden.

@Entity(tableName = "traineeRoutine")data class Routine( @PrimaryKey(autoGenerate = true) val routineId: Int, @ColumnInfo(name = "due_day") val dueDay: Date, @TypeConverters(ListConverter::class) val exercises: List)

Was zu beachten ist:

– Wenn eine Klasse mit @Entity annotiert ist, ist der Name der Tabelle der Name der Klasse. Wenn wir einen anderen Namen verwenden wollen, müssen wir die Eigenschaft tableName zusammen mit der @Entity-Annotation hinzufügen.

– Die Annotation @TypeConverters muss verwendet werden, wenn eine Eigenschaft deklariert wird, deren Typ eine benutzerdefinierte Klasse, eine Liste, ein Datumstyp oder ein anderer Typ ist, den Room und SQL nicht serialisieren können. In diesem Fall wird die Anmerkung auf der Ebene des Klassenfelds verwendet, so dass nur dieses Feld sie verwenden kann. Je nachdem, wo die Annotation platziert wird, verhält sie sich unterschiedlich, wie hier erklärt wird.

Trainee.kt

Sie stellt den Besitzer der Routine dar.

@Entity(indices = , foreignKeys = , childColumns = )])data class Trainee( @PrimaryKey(autoGenerate = true) val id: Int, val name: String, val age: Int, val gender: Int?, @Embedded val routine: Routine)

DAOs

Data Access Objects (DAOs) werden für den Zugriff auf unsere Daten verwendet, wenn wir Room implementieren. Jedes DAO muss eine Reihe von Methoden enthalten, um die Daten zu manipulieren (einfügen, aktualisieren, löschen oder abrufen).

Ein DAO kann als Schnittstelle oder als abstrakte Klasse implementiert werden. In unserem Fall verwenden wir eine Schnittstelle. Da alle DAOs im Grunde identisch sind, zeigen wir nur eine.

GenderDao.kt@Daointerface GenderDao { @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertGender(gender: Gender) @Update fun updateGender(gender: Gender) @Delete fun deleteGender(gender: Gender) @Query("SELECT * FROM Gender WHERE name == :name") fun getGenderByName(name: String): List @Query("SELECT * FROM Gender") fun getGenders(): List}

Ein paar Dinge sind zu beachten:

– Alle DAOs müssen mit @Dao annotiert werden.

– Eine Funktion, die mit @Insert, @Update oder @Delete annotiert ist, muss eine Instanz der gewünschten Klasse als Parameter erhalten, die das Objekt darstellt, das wir einfügen, aktualisieren bzw. löschen wollen.

– Im Falle von Einfüge- oder Aktualisierungsoperationen können wir die Eigenschaft onConflict verwenden, um anzugeben, was zu tun ist, wenn ein Konflikt bei der Durchführung der Operation auftritt. Die zur Verfügung stehenden Strategien sind: REPLACE, ABORT, FAIL, IGNORE und ROLLBACK.

– Wenn wir spezifische Informationen von einer oder mehreren Entitäten erhalten wollen, können wir eine Funktion mit @Query annotieren und ein SQL-Skript als Parameter bereitstellen.

Database

Repräsentiert die Datenbank. Sie enthält eine Verbindung zur aktuellen SQLite-Datenbank.

AppDatabase.kt@Database(entities = , version = 1)@TypeConverters(DateTypeConverter::class)abstract class AppDatabase : RoomDatabase() { abstract fun exerciseDao(): ExerciseDao abstract fun genderDao(): GenderDao abstract fun routineDao(): RoutineDao abstract fun traineeDao(): TraineeDao companion object { var INSTANCE: AppDatabase? = null fun getAppDataBase(context: Context): AppDatabase? { if (INSTANCE == null){ synchronized(AppDatabase::class){ INSTANCE = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "myDB").build() } } return INSTANCE } fun destroyDataBase(){ INSTANCE = null } }}

Hier ist Folgendes zu beachten:

– Dies ist eine abstrakte Klasse, die RoomDatabase erweitern muss.

– Sie muss mit @Database annotiert werden und erhält eine Liste von Entitäten mit allen Klassen, aus denen die Datenbank besteht (alle diese Klassen müssen mit @Entity annotiert werden). Wir müssen auch eine Datenbankversion angeben.

– Wir müssen eine abstrakte Funktion für jede der in der @Database-Annotation enthaltenen Entitäten deklarieren. Diese Funktion muss die entsprechende DAO (eine mit @Dao annotierte Klasse) zurückgeben.

– Schließlich deklarieren wir ein Begleitobjekt, um statischen Zugriff auf die Methode getAppDataBase zu erhalten, die uns eine Singleton-Instanz der Datenbank liefert.

Typkonverter

Typkonverter werden verwendet, wenn wir eine Eigenschaft deklarieren, die Room und SQL nicht serialisieren können. Sehen wir uns ein Beispiel für die Serialisierung eines Datentyps „Datum“ an.

DateTypeConverter.ktclass DateTypeConverter { @TypeConverter fun fromTimestamp(value: Long?): Date? { return if (value == null) null else Date(value) } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time }}

Verwendung der Room-Datenbank

Schauen wir uns nun ein sehr einfaches Beispiel für die Verwendung der Room-Datenbank an, die wir gerade erstellt haben:

MainActivity.ktclass MainActivity : AppCompatActivity() { private var db: AppDatabase? = null private var genderDao: GenderDao? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) Observable.fromCallable({ db = AppDatabase.getAppDataBase(context = this) genderDao = db?.genderDao() var gender1 = Gender(name = "Male") var gender2 = Gender(name = "Female") with(genderDao){ this?.insertGender(gender1) this?.insertGender(gender2) } db?.genderDao()?.getGenders() }).doOnNext({ list -> var finalString = "" list?.map { finalString+= it.name+" - " } tv_message.text = finalString }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe() }}

Was tun wir?

– Die Instanz der Datenbank und GenderDao holen.

– Zwei Gender-Instanzen erstellen: Male und Female.

– Einfügen der beiden erstellten Instanzen in die Datenbank.

– Abfragen der Datenbank, um alle darin gespeicherten Geschlechter zu erhalten.

– Zusammenführen der Namen aller Geschlechter, die wir aus der Datenbank erhalten haben, und Einstellen des Textes der TextView mit diesem Wert.

Room to Do More with Less

Room ist eines der wichtigsten Elemente der Android-Architekturkomponenten. Es gibt uns einen sehr robusten Rahmen für die Arbeit mit und persistente Informationen, die immer Datensicherheit und -integrität gewährleisten. Außerdem bietet es Entwicklern eine einfache Handhabung, so dass sie lesbaren und selbsterklärenden Code schreiben können. Wenn Sie mit weniger Code mehr erreichen und außerdem die Sicherheit der Benutzerdaten gewährleisten wollen, sollten Sie Room als Persistenzschicht für Ihre Anwendung verwenden.

Und das war’s! Das ist fast alles, was Sie wissen müssen, um eine Datenbank auf Android mit Room zu erstellen und zu verwenden. Den gesamten Code für dieses Projekt finden Sie hier. Vielen Dank für das Lesen dieses Android Room-Tutorials!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.