loading...

How to create an Android App: Android Room

edrome profile image EdRome Updated on ・4 min read

Hi again (x3) everyone!

We’re almost done with all app functionality, missing the saving mechanism. Once the user has filled his information, then it has to be saved on database to avoid the user fill it again and again.

Android support either SQLite or Room, I prefer the second one because adding queries and modifying columns it’s easier. Also, allow singleton instance, and asynchronous task.

As we establish on the last post, the readability is important and the way to accomplish it is by creating packages where classes are going to be stored.

Inside gradle add the following implementations. They will add android room annotations that are very important.

    implementation 'androidx.room:room-runtime:2.1.0'
    annotationProcessor 'androidx.room:room-compiler:2.1.0'
    implementation 'org.jetbrains:annotations-java5:15.0'

Android Room needs four different classes:

  1. Entity: it is table definition.
  2. DAO: it has all queries available to be performed to the table.
  3. POJO: here it is the DAO functionality
  4. Room Database: here we create the database instance.

Start creating the package database, inside it we’ll create subpackages in case we want to add more tables. I suggest to structure all your database packages like this.

+-- com.main.package
|   +-- database
|      +-- dao
|      +-- entity
|      +-- pojo
|      +-- room

First we’ll create the entity, the name I chose is profileModel. The class needs a constructor either empty or not, prefered private attributes, getter and setters of every attribute, otherwise an error will be thrown.
The table design is as described below:

Columns name Data Type Attributes
profileID Integer Primary Key, Auto generate, Non null
username String Non Null
gender String Non Null
birthday Date Non Null
photo byte[]

As you can see we add a primary key auto generated, every column might be non null except for photo, allowing the user to either select or not a profile photo.

Add the annotation for every column, and generate the constructor including getters and setters. Note the “Entity” annotation at the beginning of the class, it tells android that this class is a table and its name is profile.

@Entity(tableName = "profile")
public class profileModel {

    public profileModel(@NonNull String username, 
                        @NonNull String gender, 
                        @NonNull Date birthday, 
                        @NonNull byte[] photo) {
        this.username = username;
        this.gender = gender;
        this.birthday = birthday;
        this.photo = photo;
    }

    @NonNull
    @PrimaryKey(autoGenerate = true)
    private Integer profileId;

    @NonNull
    private String username;

    @NonNull
    private String gender;

    @NonNull
    private Date birthday;

    @NonNull
    private byte[] photo;

    @NonNull
    public Integer getProfileId() {
        return profileId;
    }

    public void setProfileId(@NonNull Integer profileId) {
        this.profileId = profileId;
    }

    @NonNull
    public String getUsername() {
        return username;
    }

    public void setUsername(@NonNull String username) {
        this.username = username;
    }

    @NonNull
    public String getGender() {
        return gender;
    }

    public void setGender(@NonNull String gender) {
        this.gender = gender;
    }

    @NonNull
    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(@NonNull Date birthday) {
        this.birthday = birthday;
    }

    @NonNull
    public byte[] getPhoto() {
        return photo;
    }

    public void setPhoto(@NonNull byte[] photo) {
        this.photo = photo;
    }
}

Tip: You can press alt+insert or right-click generate to popup a generate menu.
Tip1, Generate Costructor, getter and setter
Select all columns excluding the primary key and press ok.
Generating constructor
These steps also work for getter and setter, in that case you might select all columns, including primary key.

The DAO will be interface instead of classe, containing all table operations like inserts, queries, deletes and updates. For this tutorial purpose, we'll define an insert, an update and a query.

@Dao
public interface profileDAO {

    @Insert
    void insert(profileModel profile);

    @Update
    void update(profileModel profile);

    @Query("SELECT * FROM profile WHERE profileId = :id")
    profileModel getProfile(Integer id);

}

Once the entity and DAO are create, we add the database room class. It has to be abstract, with an annotation at the top of it. This annotation indicates the entities contained inside the database, along with a version number, that has to increase each time you do a change on the entity, and an exportSchema indicator, it is defined as false for this series.

@Database(entities = {profileModel.class}, version = 1, exportSchema = false)
public abstract class databaseRoom extends RoomDatabase {

    public abstract profileDAO foodsDao();

    public static volatile databaseRoom INSTANCE;

    public static databaseRoom getDatabase(final Context context){
        if (INSTANCE == null){
            synchronized (databaseRoom.class){
                if (INSTANCE == null){
                    INSTANCE = Room.databaseBuilder(
                                   context.getApplicationContext(),
                                   databaseRoom.class,
                                   "profile_database")
                               .fallbackToDestructiveMigration()
                               .allowMainThreadQueries()
                               .build();
                }
            }
        }
        return INSTANCE;
    }

}

When all files are ready, then we create a POJO class that will be the one used to perform operations inside our database.

public class profilePOJO {

    private profileDAO mProfileDao;
    private profileModel mProfile;

    public profilePOJO(Application application) {
        databaseRoom db = databaseRoom.getDatabase(application);
        mProfileDao = db.foodsDao();
    }

    public profileModel getProfile(Integer id) {
        return mProfileDao.getProfile(id);
    }

    public void insert(profileModel profile){
        new insertAsyncTask(mProfileDao).execute(profile);
    }

    private static class insertAsyncTask extends AsyncTask<profileModel, Void, Void> {

        private profileDAO mAsyncTaskDao;

        insertAsyncTask(profileDAO dao){
            mAsyncTaskDao = dao;
        }

        @Override
        protected Void doInBackground(final profileModel... profiles) {
            mAsyncTaskDao.insert(profiles[0]);
            return null;
        }
    }
}

Aaand.... we're going to leave it here or the post will be to large for reading.

As always, I share the link to this project on GitHub. Feel free to use it as you wish.

Edit: I forgot to add Dao annotation. Sorry for that

Discussion

pic
Editor guide