This post shows how to use greenDAO ORM for SQLite in Android using a demo app. We start with a simple Android project in the Android Studio, create a few entities, save to and read data from the database.
Requirements
This post’s requirements include Android Studio 4.1.2, Android API 30, Gradle 6.5, and Build Tools 30.0.2. The Android project is a simple project created using the Basic Activity Template.
Update build.gradle files – Both for Project And Module
For the project build.gradle, add the following highlighted line, which enables us to use the greenDAO plugin within Android Studio.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { google() jcenter() } dependencies { classpath "com.android.tools.build:gradle:4.1.2" classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { google() jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } |
On the other hand, for the build.gradle for the module (or app), add the following two highlighted lines. The first line enables greenDAO to generate DAO files and update our entity classes for SQLite; the second line defines the greenDAO dependency for our Android app both for compile-time and runtime.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | plugins { id 'com.android.application' } android { compileSdkVersion 30 buildToolsVersion "30.0.2" defaultConfig { applicationId "com.turreta.greendaogeneraldemo" minSdkVersion 29 targetSdkVersion 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } apply plugin: 'org.greenrobot.greendao' } dependencies { implementation 'org.greenrobot:greendao:3.3.0' implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.navigation:navigation-fragment:2.3.3' implementation 'androidx.navigation:navigation-ui:2.3.3' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' } |
By the way, don’t forget to “Sync Now” the files to allow the changes to take effect.
Entities for greenDAO ORM
Then, we have the following entities – Person and Pet classes. The Person entity has a unique key constraint on both firstName and lastName fields. Meaning these fields must be unique for each row. The class also has an auto-incrementing @Id field and @NotNull fields.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package com.turreta.greendaogeneraldemo.entity; import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Index; import org.greenrobot.greendao.annotation.NotNull; import org.greenrobot.greendao.annotation.ToMany; import java.util.List; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.DaoException; @Entity(indexes = { @Index(value = "firstName,lastName", unique = true) }) public class Person { @Id(autoincrement = true) private Long id; @NotNull private String firstName; @NotNull private String lastName; @ToMany(referencedJoinProperty = "personId") private List<Pet> petList; } |
The Pet entity has the following codes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package com.turreta.greendaogeneraldemo.entity; import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.NotNull; import org.greenrobot.greendao.annotation.ToOne; import lombok.ToString; import org.greenrobot.greendao.annotation.Generated; import org.greenrobot.greendao.DaoException; @Entity public class Pet { @Id(autoincrement = true) private Long id; @NotNull private String petName; @NotNull private Long personId; @ToString.Exclude @ToOne(joinProperty = "personId") private Person person; } |
The entities have a bi-directional relationship with each other – one Person can have at least one Pet, and all Pet entities have references back to the Person entity!
Next, we need to rebuild the whole project via the Build > Make Project or Build > Rebuild Project menu option for GreenDAO ORM to update our entities and generate DAO classes, as shown below. Once we rebuilt the project, there are now four DAO-related classes, and our entities have been modified to have these new instance variables and methods.
Create Database via greenDAO ORM on Start-Up
There are two places where we can create the database for our Android app – either create the database in the onCreate() method of a subclass of Application or the main Activity class. The following codes create an SQLite database via greenDAO ORM on start-up.
1 2 3 4 5 6 7 | ... DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "greendao-demo-db"); Database db = helper.getWritableDb(); // We will use daoSession for creating, deleting, updating, and retrieving records DaoSession daoSession = new DaoMaster(db).newSession(); ... |
When we start up our Android app, greenDAO ORM creates an SQLite database file “greendao-demo-db” if that file doesn’t exist yet in /data/data/com.turreta.greendaogeneraldemo/databases. If the file already exists, greenDAO ORM uses it.
Add, Edit, And Delete Entities in SQLite
From here on, we use an instance of DaoSession. Typically, we only have one instance of this class for the Android app’s life duration. Through that instance, we can access the DAO for each of our entity classes. Consider the following codes.
To create a Person record, we instantiate a Person object, set its properties, and pass it as an argument to its PersonDAO class’ save method. Note that we are using the same instance of DaoSession to get the appropriate DAO instance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ... Person person = new Person(); person.setFirstName("Karl"); person.setLastName("San Gabriel"); // Get an PersonDAO from an existing DAO session PersonDao personDao = daoSession.getPersonDao(); personDao.save(person); // Get an PetDAO from an existing DAO session PetDao petDao = daoSession.getPetDao(); Pet pet1 = new Pet(); pet1.setPetName("Blue"); pet1.setPerson(person); petDao.save(pet1); List<Pet> petList = person.getPetList(); for (Pet pet : petList) { // Outputs Blue Log.d(TAG, "onCreate: " + pet.getPetName()); } ... |
To update an entity, we first load it using the load method. Then, save the changes using the save() method. Another thing to note when using greenDAO, there is no cascade update of entities right now. We need to save or update each entity explicitly.
1 2 3 4 5 | ... Person personToUpdate = personDao.load(1L); PersonToUpdate.setFirstName("New First Name"); personDao.save(personToUpdate); ... |
For deletion, greenDAO ORM doesn’t support cascade deletion as of this writing. Therefore, we need to delete records that hold foreign keys before deleting the records the keys refer to. For example, delete all Pet records before deleting the Person record that they refer to.
1 2 3 4 5 6 7 8 | ... Person personToDelete = personDao.load(1L); List<Pet> petList = personToDelete.getPetList(); for (Pet pet : petList) { petDao.delete(pet); } personDao.deleteByKey(1L); ... |
For further readings, please check out the greenDAO ORM documentation.