Skip to content Skip to sidebar Skip to footer

Implementing The Room Database (android)

I like to know how to properly integrate the Room Library within an Android Application. Some articles I have seen uses a Singleton approach using a Respository for database calls,

Solution 1:

Room Basics

The Room library acts as an abstract layer for underlying SQLite database. Thus, Room annotations are used:

  1. To Database and Entities where entities are POJO classes representing table structures.
  2. To specify operation for retrieval, updation and deletion.
  3. To add constraints, such as foreign keys.
  4. Support for LiveData.

There are 3 major components in Room

  1. Entity : A class annotated with the @Entity annotation is mapped to a table in database. Every entity is persisted in its own table and every field in class represents the column name.

tableName attribute is used to define the name of the table Every entity class must have at-least one Primary Key field, annotated with @PrimaryKey Fields in entity class can be annotated with @ColumnInfo(name = “name_of_column”) annotation to give specific column names

  1. DAO : Data Access Object is either be an interface or an abstract class annotated with @Doa annotation, containing all the methods to define the operations to be performed on data. The methods can be annotated with

@Query to retrieve data from database

@Insert to insert data into database

@Delete to delete data from database

@Update to update data in database

  1. Database : Database is a container for tables. An abstract class annotated with @Database annotation is used to create a database with given name along with database version.

To understand better look at this diagram

Add these dependencies :

    dependencies {
    // Room dependencies
      compile 'android.arch.persistence.room:runtime:1.0.0'
      annotationProcessor 'android.arch.persistence.room:compiler:1.0.0'
    }

Create Entity

Before creating a database, Let's create an Entity, named as Note and later, Objects of this class will be added to database.

@EntitypublicclassNote {

    @PrimaryKey(autoGenerate = true)
    private int note_id;

    @ColumnInfo(name = "note_content") // column name will be "note_content" instead of "content" in tableprivateString content;

    privateString title;

    privatepublicNote(int note_id, String content, String title) {
        this.note_id = note_id;
        this.content = content;
        this.title = title;
    }

    public int getNote_id() {
        return note_id;
    }

    publicvoidsetNote_id(int note_id) {
        this.note_id = note_id;
    }

    publicStringgetContent() {
        return content;
    }

    publicvoidsetContent(String content) {
        this.content = content;
    }

    publicStringgetTitle() {
        return title;
    }

    publicvoidsetTitle(String title) {
        this.title = title;
    }

    @Overridepublicbooleanequals(Object o) {
        if (this == o) returntrue;
        if (!(o instanceofNote)) returnfalse;

        Note note = (Note) o;

        if (note_id != note.note_id) returnfalse;
        return title != null ? title.equals(note.title) : note.title == null;
    }



    @Overridepublic int hashCode() {
        int result = note_id;
        result = 31 * result + (title != null ? title.hashCode() : 0);
        return result;
    }

    @OverridepublicStringtoString() {
        return"Note{" +
                "note_id=" + note_id +
                ", content='" + content + '\'' +
                ", title='" + title + '\'' +
                '}';
    }}

Creating DAOs

DAOs define all methods to access database, annotated with @Dao annotation. The DAO acts as a contract to perform CRUD operations on data within a database.

@DaopublicinterfaceNoteDao {
  @Query("SELECT * FROM user "+ Constants.TABLE_NAME_NOTE)
  List<Note> getAll();


  /*
  * Insert the object in database
  * @param note, object to be inserted
  */@Insertvoidinsert(Note note);

  /*
  * update the object in database
  * @param note, object to be updated
  */@Updatevoidupdate(Note repos);

  /*
  * delete the object from database
  * @param note, object to be deleted
  */@Deletevoiddelete(Note note);

  /*
  * delete list of objects from database
  * @param note, array of objects to be deleted
  */@Deletevoiddelete(Note... note);      // Note... is varargs, here note is an array

}

Create Database

Now, we have table defined as Entity and CRUD methods defined via NoteDao. The last piece of the database puzzle is the database itself.

@Database(entities = { Note.class }, version = 1)
publicabstractclassNoteDatabaseextendsRoomDatabase {

publicabstract NoteDao getNoteDao();

privatestatic NoteDatabase noteDB;

publicstatic NoteDatabase getInstance(Context context) {
if (null == noteDB) {
noteDB = buildDatabaseInstance(context);
}
return noteDB;
}

privatestatic NoteDatabase buildDatabaseInstance(Context context) {
return Room.databaseBuilder(context,
NoteDatabase.class,
Constants.DB_NAME)
.allowMainThreadQueries().build();
}

publicvoidcleanUp(){
noteDB = null;
}

}

Implement Database Interactions

The below snippet will demonstrate the working of insert, update, and delete functionality using the Room database.

publicclassAddNoteActivityextendsAppCompatActivity {

privateTextInputEditText et_title,et_content;
privateNoteDatabase noteDatabase;
privateNote note;

@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_note);
et_title = findViewById(R.id.et_title);
et_content = findViewById(R.id.et_content);
noteDatabase = NoteDatabase.getInstance(AddNoteActivity.this);
Button button = findViewById(R.id.but_save);

      button.setOnClickListener(newView.OnClickListener() {
          @OverridepublicvoidonClick(View view) {
            // fetch data and create note object
                note = newNote(et_content.getText().toString(),
                        et_title.getText().toString());

                // create worker thread to insert data into databasenewInsertTask(AddNoteActivity.this,note).execute();
          }
      });

}

privatevoidsetResult(Note note, int flag){
setResult(flag,newIntent().putExtra("note",note));
finish();
}

privatestaticclassInsertTaskextendsAsyncTask<Void,Void,Boolean> {

      privateWeakReference<AddNoteActivity> activityReference;
      privateNote note;

      // only retain a weak reference to the activityInsertTask(AddNoteActivity context, Note note) {
          activityReference = newWeakReference<>(context);
          this.note = note;
      }

      // doInBackground methods runs on a worker thread@OverrideprotectedBooleandoInBackground(Void... objs) {
          activityReference.get().noteDatabase.getNoteDao().insertNote(note);
          returntrue;
      }

        // onPostExecute runs on main thread@OverrideprotectedvoidonPostExecute(Boolean bool) {
          if (bool){
              activityReference.get().setResult(note,1);
          }
      }

}

}

Retrieve And Display NoteList

publicclassNoteListActivityextendsAppCompatActivityimplementsNotesAdapter.OnNoteItemClick{

private TextView textViewMsg;
private RecyclerView recyclerView;
private NoteDatabase noteDatabase;
private List<Note> notes;
private NotesAdapter notesAdapter;
privateint pos;

@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeVies();
displayList();
}

privatevoiddisplayList(){
// initialize database instance
noteDatabase = NoteDatabase.getInstance(NoteListActivity.this);
// fetch list of notes in background threadnewRetrieveTask(this).execute();
}

privatestaticclassRetrieveTaskextendsAsyncTask<Void,Void,List<Note>>{

      private WeakReference<NoteListActivity> activityReference;

      // only retain a weak reference to the activity
      RetrieveTask(NoteListActivity context) {
          activityReference = newWeakReference<>(context);
      }

      @Overrideprotected List<Note> doInBackground(Void... voids) {
          if (activityReference.get()!=null)
              return activityReference.get().noteDatabase.getNoteDao().getNotes();
          elsereturnnull;
      }

      @OverrideprotectedvoidonPostExecute(List<Note> notes) {
          if (notes!=null && notes.size()>0 ){
              activityReference.get().notes = notes;

              // hides empty text view
              activityReference.get().textViewMsg.setVisibility(View.GONE);

              // create and set the adapter on RecyclerView instance to display list
              activityReference.get().notesAdapter = newNotesAdapter(notes,activityReference.get());
              activityReference.get().recyclerView.setAdapter(activityReference.get().notesAdapter);
          }
      }

}

privatevoidinitializeVies(){
Toolbartoolbar= (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
textViewMsg = (TextView) findViewById(R.id.tv\_\_empty);

      // Action button to add noteFloatingActionButtonfab= (FloatingActionButton) findViewById(R.id.fab);
      fab.setOnClickListener(listener);
      recyclerView = findViewById(R.id.recycler_view);
      recyclerView.setLayoutManager(newLinearLayoutManager(NoteListActivity.this));

}

}

Update Note

publicclassAddNoteActivityextendsAppCompatActivity {

    private TextInputEditText et_title,et_content;
    private NoteDatabase noteDatabase;
    private Note note;
    privateboolean update;

    @OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_note);
        et_title = findViewById(R.id.et_title);
        et_content = findViewById(R.id.et_content);
        noteDatabase = NoteDatabase.getInstance(AddNoteActivity.this);
        Buttonbutton= findViewById(R.id.but_save);
        if ( (note = (Note) getIntent().getSerializableExtra("note"))!=null ){
            getSupportActionBar().setTitle("Update Note");
            update = true;
            button.setText("Update");
            et_title.setText(note.getTitle());
            et_content.setText(note.getContent());
        }

        button.setOnClickListener(newView.OnClickListener() {
            @OverridepublicvoidonClick(View view) {
            note.setContent(et_content.getText().toString());
            note.setTitle(et_title.getText().toString());
            noteDatabase.getNoteDao().updateNote(note);
            }
        });
    }

}

Delete Note

noteDatabase.getNoteDao().deleteNote(notes.get(pos));
adapterObj.notifyDataSetChanged();

Solution 2:

ROOM Database

  • Room is an ORM (Object Relational Mapper) for SQLite database in Android developement and part of Android Jetpack.
  • Provides an abstraction layer over SQLite database
  • Amount of boilerplate code is reduced
  • Compile-time verification of SQL queries

ROOM Database components

  • It has 3 main components Entity, Database, DAO.
  • Entity is data class annotated with @Entity is like creating a table in SQLite and the variables in the model class are like columns in the table.
  • Database is an abstract class which extends RoomDatabase and has list of entities associated with the database.
  • DAO(Data Access Object) is an interface which defines the operations to be performed in our database.

ROOM Database Implementation

  • Step 1 creating Entity data class

    @Entity(tableName = "yourOwnTableName")

    data class LocalData(

    val column1: String?,
    
      val column2: String?,  
    
      @PrimaryKey(autoGenerate = true)val product_local_id: Int?= null

    )

  • Step 2 creating Database

    @Database(entities = [LocalData::class], version = 1, exportSchema = false) @TypeConverters

    abstract class LocalDB : RoomDatabase() {

    abstractfunlocalDataDao() : LocalDataDAO
    
      companionobject{
    
          privatevar instance : LocalDB ? = nullfungetInstance(context: Context) : LocalDB ?{
              if(instance == null){
                  synchronized(LocalDB ::class){
                      instance = Room.databaseBuilder(context.applicationContext, LocalDB::class.java, "localBD.db").allowMainThreadQueries().build()
                  }
              }
              return instance
          }
    
          fundestroyInstance(){
              instance = null
          }
      }
    

    }

  • Step 3 creating DAO

    @Dao interface LocalDAO {

    @InsertfuninsertData(productEntity: LocalData) : Long@DeletefundeleteData(productEntity: LocalData) : Int@Query("Select * from yourOwnTableName")funshowAllProducts(): List<LocalData>
    
      @Query("SELECT COUNT(*) FROM yourOwnTableName")funtotalProducts(): Long

    }

  • Step 4 is optional is creating repository

class ProductRepository(context: Context) {

var dbms : LocalDAO = LocalDB.getInstance(context)?.localDataDao()!!

funinsertData(productEntity: LocalData) : Long{
    return dbms.insertData(productEntity)
}

fundeleteData(productEntity: LocalData) : Int{
    return dbms.deleteData(productEntity)
}

fungetAllData() : List<LocalData> {
    return dbms.showAllProducts()
}

funcheckProductExist(id : Int) : Boolean{
    return dbms.exists(id)
}

funtotalProductsInCart() : Long{
    return dbms.totalProducts()
}

}

Solution 3:

What about consulting the official documentation.

Solution 4:

I think the best place is codelabs, it has a simple implementation, as well as a more complex one. All using Room.

Edit: Above links seems to be removed. Here are a couple of resources to replace that:

  1. Android room with a view
  2. Room + LiveData + ViewModel

Post a Comment for "Implementing The Room Database (android)"