Database with Room using RxJava

Google release new library Room which is layer over SQLite to allow fluent database access while harnessing the full power of SQLite. For more information about Room check the link.

In this post we will learn how to implement Room with nice way without touching UI thread, everything is in background using RxJava.

we need to import the following libraries in gradle :

// for room
compile "android.arch.persistence.room:runtime:1.0.0-beta1"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0-beta1"
// for rxJava
compile "io.reactivex.rxjava2:rxjava:2.0.6"
compile "io.reactivex.rxjava2:rxandroid:2.0.1"

First we will create our entity which is User as for example.

@Entity(tableName = "users")
public class User {
@PrimaryKey(autoGenerate = true)
private int uid;

@ColumnInfo(name = "first_name")
private String firstName;

@ColumnInfo(name = "last_name")
private String lastName;

public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

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;
}
}

Next we need to new interface called UserDao as Google documentation.

@Dao
public interface UserDao {
@Query("SELECT * FROM users")
Maybe<List<User>> getAll();

@Query("SELECT * FROM users WHERE uid IN (:userIds)")
Flowable<List<User>> loadAllByIds(int[] userIds);

@Query("SELECT * FROM users WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
User findByName(String first, String last);

@Query("SELECT * FROM users where uid = :id")
Maybe<User> findById(int id);


@Insert
void insertAll(User... users);

@Delete
void delete(User user);

@Update
public void updateUsers(User... users);
}

Then add AppDatabase.class

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}

In Our example I use class called LocalCacheManager.class responsible to handle everything related to database.

public class LocalCacheManager {
private static final String DB_NAME = "database-name";
private Context context;
private static LocalCacheManager _instance;
private AppDatabase db;

public static LocalCacheManager getInstance(Context context) {
if (_instance == null) {
_instance = new LocalCacheManager(context);
}
return _instance;
}

public LocalCacheManager(Context context) {
this.context = context;
db = Room.databaseBuilder(context, AppDatabase.class, DB_NAME).build();
}

public void getUsers(final DatabaseCallback databaseCallback) {
db.userDao().getAll().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<List<User>>() {
@Override
public void accept(@io.reactivex.annotations.NonNull List<User> users) throws Exception {
databaseCallback.onUsersLoaded(users);

}
});
}

public void addUser(final DatabaseCallback databaseCallback, final String firstName, final String lastName) {
Completable.fromAction(new Action() {
@Override
public void run() throws Exception {
User user = new User(firstName, lastName);
db.userDao().insertAll(user);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}

@Override
public void onComplete() {
databaseCallback.onUserAdded();
}

@Override
public void onError(Throwable e) {
databaseCallback.onDataNotAvailable();
}
});
}

public void deleteUser(final DatabaseCallback databaseCallback, final User user) {
Completable.fromAction(new Action() {
@Override
public void run() throws Exception {
db.userDao().delete(user);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onComplete() {
databaseCallback.onUserDeleted();
}

@Override
public void onError(Throwable e) {
databaseCallback.onDataNotAvailable();
}
});
}


public void updateUser(final DatabaseCallback databaseCallback, final User user) {
user.setFirstName("first name first name");
user.setLastName("last name last name");
Completable.fromAction(new Action() {
@Override
public void run() throws Exception {
db.userDao().updateUsers(user);
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onComplete() {
databaseCallback.onUserUpdated();
}

@Override
public void onError(Throwable e) {
databaseCallback.onDataNotAvailable();
}
});
}
}

As we can see i created class called DatabaseCallback as callback for adding or delete from Room using RxJava.

After this implementation you can use Room with RxJava and everything will execute on new thread.

You can find complete source code here.

Happy Coding!