Android Architecture Components — Part 1 (Room)

Aman Shandilya
AndroidPub
Published in
5 min readMay 19, 2018

If you have been working with android, then you will be familiar with SQLite Database which is an inbuilt local database for android.

žRemember the amount of boilerplate code you had to write to create and manipulate even a very small database? You had to define the database structure, create an SQLiteOpenHelper class etc.

There in SQLite database no compile time verification of raw SQL quires. Also you have to maintain the CursorAdapter to fetch data from SQLite database. And if your schema get changed you need to update the affected SQL quires.

Above are some problems with SQLite databases.

First of all we’ll point out some benefits of the Room persistence library from android architecture components and then we’ll create a very basic android example using SQLite with Room.

Let’s start Room from here:

žRoom provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

žCompile-time verification of SQL queries — each query and entity is checked at the compile time, so there’s no risk of run-time error that might crash your app (and it doesn’t check only syntax, but also e.g. missing tables).

žVery little boilerplate code.

There are some basic needs of Room:

  1. @Entity(tableName = “name_of_your_table”): this is an annotated class that describes a database table. Each @Entity class represents an entity in a table. Annotate your class declaration to indicate that it’s an entity. Specify the name of the table if you want it to be different from the name of the class.
  2. ž@PrimaryKey: Every entity needs a primary key. To keep things simple, each word acts as its own primary key.
  3. ž@ColumnInfo(name = “name_of-your_column”): Specify the name of the column in the table if you want it to be different from the name of the member variable.
  4. žEvery field that’s stored in the database needs to be either public or have a “getter” method.
  5. DAO: Data access object. A mapping of SQL queries to functions. You used to have to define these painstakingly in your SQLiteOpenHelper class. When you use a DAO, you call the methods, and Room takes care of the rest. žIn the DAO (data access object), you specify SQL queries and associate them with method calls. The compiler checks the SQL and generates queries from convenience annotations for common queries, such as @Insert, @Delete etc. The DAO must be an interface or abstract class.
  6. žRoom database: Database layer on top of SQLite database that takes care of mundane tasks that you used to handle with an SQLiteOpenHelper. Database holder that serves as an access point to the underlying SQLite database. The Room database uses the DAO to issue queries to the SQLite database.

Let’s Create a basic example:

Add dependencies:
In your app level build.gradle file add these two dependencies for Room library.

compile ‘android.arch.persistence.room:runtime:1.0.0;
annotationProcessor ‘android.arch.persistence.room:compiler:’1.0.0;

Create Entity:
import
android.arch.persistence.room.ColumnInfo;
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;
@Entity
public class User {
@PrimaryKey(autoGenerate = true)
private int uid;
@ColumnInfo(name = "first_name")
private String firstName;
@ColumnInfo(name = "last_name")
private String lastName;
@ColumnInfo(name = "age")
private int age;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

As you can see in above code I am creating a Entity by using @Entity annotation. This annotation defines user class as a database table and data in it will be saved in this table. In User entity there I have defined a primary key by using @PrimaryKey(autoGenerate = true) and three other columns by using @ColumnInfo(name = “name_of_column”).

Now I am creating DAO for User entity.

@Dao
public interface UserDao {
@Query("select * from USER")
List<User> getAll();
@Query("SELECT * FROM user where first_name LIKE :firstName AND last_name LIKE :lastName")
User findByName(String firstName, String lastName);
@Query("SELECT COUNT(*) from user")
int countUsers();
@Insert
void insert(User user);
@Delete
void delete(User user);
}

In the above code snippet you can see DAO is an interface and is annotated by @DAO annotation. By this annotation room database treat this interface as a DAO. In UserDao interface I am defining raw queries by using @Query annotation and direct method to insert and delete user from database by using @Insert and @Delete annotation respectively.

As we have table and quries for database now finally we will create RoomDatabase.

@Database(entities = {User.class}, version = 1, exportSchema = false)public abstract class AppDatabase extends RoomDatabase {private static AppDatabase INSTANCE;
public abstract UserDao userDao();
public static AppDatabase getAppDatabase(Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE=Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "user-database")
.allowMainThreadQueries().build();
}
}
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
}

As you can see I have created a singleton abstract class by extending RoomDatabase class. As we already know Database class must be abstract and must extend RoomDatabase class. I am using Singletom pattern because I want only one instance of AppDatabase class in whole application. Above AppDatabase class is annotated by-
@Database(entities = {User.class}, version = 1, exportSchema = false).
Here in above code snippet entities is an array of all entities those will be added in your database then there is database version number after that exportSchema=false.

Now lets add database in our MainActivity class. You can find the complete code here. But in this doc I am just pasting my MainActivity class just for the understanding.

public class MainActivity extends AppCompatActivity {private Button btnAdd;
private EditText etFname, etLname, etAge;
private RecyclerView recyclerView;
private AppDatabase appDatabase;
private UserDao userDao;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

appDatabase = AppDatabase.getAppDatabase(MainActivity.this);
userDao = appDatabase.userDao();

btnAdd = findViewById(R.id.btn_adduser);
etFname = findViewById(R.id.et_fname);
etLname = findViewById(R.id.et_lname);
etAge = findViewById(R.id.et_age);
recyclerView = findViewById(R.id.recyclerview);
RecyclerView.LayoutManager linearLayoutManager = new
LinearLayoutManager(MainActivity.this);
recyclerView.setLayoutManager(linearLayoutManager);
List<User> userList = new ArrayList<>();
myAdapter = new MyAdapter(userList, MainActivity.this);
recyclerView.setAdapter(myAdapter);
userList = userDao.getAll();
myAdapter.refreshList(userList);
btnAdd.setOnClickListener((view) -> {
User user = new User();
user.setFirstName(etFname.getText().toString());
user.setLastName(etLname.getText().toString());
user.setAge(Integer.parseInt(etAge.getText().toString()));
userDao.insertAll(user);
}); }
}

In above class I am creating instance of AppDatabse class which is a Singleton class that extend RoomDatabse class.

Find the complete code here. In this code I am using LiveData also but we will talk about LiveData and ViewModel in next part with the same example till then Happy Coding :)

Thanks for reading.

--

--

Aman Shandilya
AndroidPub

Never be serious by Nature, Always be serious for Nature.