Introduction à Room — Architecture Components

CBTW
L’Actualité Tech — Blog CBTW
5 min readNov 20, 2017

Room : Exploration de la librairie Android fournissant des outils pour créer, requêter et manipuler plus facilement des bases de données SQLite

Room Architecture Components
Bibliothèque — Photo Janko Ferlič — Room Architecture Components

Un vent de fraîcheur est passé sur la planète Android au printemps dernier.

En effet, lors de la Google IO 2017, Google a annoncé un ensemble de librairies permettant de produire un code de meilleure qualité, plus robuste et testable plus facilement en comblant certaines lacunes du framework Android : Architecture Components.

Les Architectures Components se divisent en quatre catégories :

LifeCycle : Un set d’APIs permettant de mieux maîtriser les cycles de vie des activités et fragments.

LiveData : Une classe faisant office de wrapper permettant d’observer des changements de données.

ViewModel : Une classe permettant de garder des données ou un état sans qu’elle ne soit impactée par un changement de configuration (rotation de l’écran…)

Enfin Room : Une librairie fournissant des outils pour créer, requêter et manipuler plus facilement des bases de données SQLite. C’est sur cette dernière que nous nous focaliserons dans ce billet, à travers un exemple d’utilisation assez simple.

Comme décrit précédemment, Room est une librairie prenant la forme d’une couche d’abstraction au-dessus d’une base SQLite, permettant ainsi de créer très facilement une base de données, ses tables et de mettre à jour ses données. Dans l’esprit, Room est assez similaire à d’autres ORMs existants sur Android tels que GreenDAO ou encore ORMLite. Si vous avez déjà une expérience avec ces derniers, vous ne devriez pas être dépaysés sur Room.

Configuration

Pour commencer, ajoutez Room à votre projet puis, ajoutez la référence au maven Google à votre fichier build.gradle, situé au plus haut niveau de votre workspace :

allprojects {
repositories {
maven { url 'https://maven.google.com' }
jcenter()
}
}

Ajoutez ensuite la dépendance à votre build.gradleau niveau de votre module app :

compile 'android.arch.persistence.room:runtime:1.0.0-alpha9'
compile 'android.arch.persistence.room:rxjava2:1.0.0-alpha9'
kapt "android.arch.persistence.room:compiler:1.0.0-alpha9"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha9"

Définition des entités

Dans cet exemple, nous prendrons comme modèle un POJO (ou plutôt un POKO… Vous l’avez, vous l’avez ?) décrivant des news récupérées via un flux RSS :

const val TABLE_NAME = "Articles"

@Entity(tableName = TABLE_NAME)
class Article() : Comparable<Article> {

@PrimaryKey(autoGenerate = true)
var id: Long = 0
var title: String? = null
var date: Date? = null
var description: String? = null
var image: String? = null
var isRead: Boolean = false

override fun compareTo(other: Article): Int {
return other.date!!.compareTo(this.date)
}

constructor(title: String, date: Date, description: String, image: String, id: Long, read: Boolean) : this() {
this.title = title
this.date = date
this.description = description
this.image = image
this.id = id
this.isRead = read
}
}

L’annotation @Entity signifie que la classe Article correspondra à une table nommée "Articles".

Notons également l’annotation @PrimaryKeyqui désigne la clé primaire de la table, qui sera ici un Long auto généré.

Déclaration des interfaces DAO

Room a ensuite besoin de connaître la façon dont vous désirez récupérer des articles en base. Nous allons pour cela créer une interface ArticleDAO qui contiendra, entre autres, les requêtes SQL dont vous aurez besoin pour manipuler les données de la table Articles. Car oui, vous aurez toujours à écrire vos requêtes SQL avec Room à la différence près que vous bénéficierez d'un contrôle de la syntaxe à la compilation. En effet, les requêtes étant précompilées au build de l'application, vous ne pourrez pas lancer votre app si votre DAO contient des requêtes erronées.

La déclaration d’un DAO Room se fait grâce à l’annotation @Dao :

@Dao
interface ArticleDAO {

@Query("Select * FROM Articles")
fun getAllArticles(): Flowable<List<Article>>

@Insert(onConflict = REPLACE)
fun addArticles(article: Article)

@Insert(onConflict = REPLACE)
fun addArticles(articles: List<Article>)

@Delete
fun deleteArticle(article: Article)

@Query("Delete from Articles")
fun deleteAllArticle()

}

Les annotations @Query désignent les requêtes SQL de l'utilisateur. @Insertet @Delete sont utilisées, comme leur nom l'indique, pour insérer ou effacer des lignes dans la table Articles. @Updateest également disponible pour les méthodes visant à mettre à jour des données de la table.

Notons que les requêtes de sélection renvoient par défaut des LiveData [une classe faisant office de wrapper permettant d’observer des changements de données], à savoir des données pouvant être observables suivant les principes de la programmation réactive. Room se mariera donc parfaitement avec RxJava2 ou encore RxKotlin dans votre projet. La première est par ailleurs désormais fournie avec Room comme vous avez dû le remarquer avec les dépendances renseignées en début de billet.

Création de la base de données

Avant de créer votre base de données, vous devez la décrire via une classe héritant de la classe RoomDatabase.

@Database(entities = arrayOf(Article::class), version = 1)
@TypeConverters(DateTypeAdapter::class)
abstract class RSSReaderDatabase : RoomDatabase() {

abstract fun articleDAO(): ArticleDAO
}

L’annotation @Databasedécrit le fait qu'il s'agit d'une base de données Room. Elle permet également de renseigner d'autres attributs tels que la liste des tables, ou encore la version de la base. Cette dernière sera à incrémenter en cas de mise à jour. La méthode articleDAO()sera le moyen de récupérer un objet ArticleDAO permettant d'exécuter les requêtes que nous avons décrites dans l'interface éponyme un peu plus haut.

Dans cet exemple, nous stockerons un objet RoomDatabase en tant que singleton, au niveau de la classe Application du projet :

public class RSSReaderApp : Application() {
override fun onCreate() {
super.onCreate()
RSSReaderApp.database = Room.databaseBuilder(this, RSSReaderDatabase::class.java, "articles.db").build();
}

companion object {
var database: RSSReaderDatabase? = null
}
}

Nous sommes à présent prêts à insérer/récupérer des données en base tout simplement en récupérant un objet ArticleDAO à partir de notre singleton. Comme précisé ci-dessus, nous utiliserons ici RxJava2 afin, d'une part d'être notifié de tout changement sur les données sans refaire une requête, et, d’autre part, de s'assurer que les objets seront émis/insérés dans un nouveau thread. Voici un exemple d'insertion d'une liste d'objets Article:

Observable.fromCallable {
RSSReaderApp.database?.articleDAO()
?.addArticles(articles)
}
.subscribeOn(Schedulers.newThread())
.subscribe()

Dans l’autre sens, voici à quoi ressemblera la récupération de données en base :

val observable = RSSReaderApp.database?.articleDAO()?.getAllArticles()
?.subscribeOn(Schedulers.newThread())
?.observeOn(AndroidSchedulers.mainThread())

L’émission de nos objets Article sera alors déclenchée en abonnant un Subscriber à la variable observable que nous venons de créer :

observable?.subscribe { listArticles -> refreshArticles(listArticles) }

La liste d’articles ainsi récupérée est passée en paramètre à la méthode refreshArticles()

Et c’est tout !

Vous savez désormais créer une base de données, y insérer des données et les récupérer en utilisant Room.

Nous publions régulièrement des articles sur des sujets de développement produit web et mobile, data et analytics, sécurité, cloud, hyperautomatisation et digital workplace.
Suivez-nous pour être notifié des prochains articles et réaliser votre veille professionnelle.

Retrouvez aussi nos publications et notre actualité via notre newsletter, ainsi que nos différents réseaux sociaux : LinkedIn, Twitter, Youtube, Twitch et Instagram

Vous souhaitez en savoir plus ? Consultez notre site web et nos offres d’emploi.

L’auteur

Loïc
Lead developer Android, Original Raggamuffin

--

--

CBTW
L’Actualité Tech — Blog CBTW

Nos experts partagent leur vision et leur veille en développement web et mobile, data et analytics, sécurité, cloud, hyperautomation et digital workplace.