Home Android & Kotlin Books Saving Data on Android

9
The DAO Pattern Written by Subhrajyoti Sen

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

In the previous chapter, you learned about different kinds of relations, such as one-to-one, one-to-many and many-to-many. You also learned how to create them using annotations.

In this chapter, you’ll learn how to retrieve, insert, delete and update data from your database using Database Access Objects (DAO).

Along the way, you will also learn:

  • What DAOs are and how they work.
  • How to create DAOs using Room annotations.
  • How to prepopulate the database using a provider class.
  • How to perform INSERT INTO queries using @Insert annotated methods.
  • How to perform DELETE FROM queries using @Deleteannotated methods.
  • How to use @Query to read data from the database.

Ready? Dive in!

Getting started

Download the starter project attached to this chapter and open it using Android Studio 4.2 or above. Once Gradle finishes building your project, take some time to familiarize yourself with the code. If you have been following along, to this point, you should already be familiar with the project since it is the same as the final project from the last chapter. If you are just getting started, here is a quick recap of the code:

  • The data package contains two packages: db and model. The db package contains the QuestionDatabase class, which defines your Room database. The model package contains your entities: Question and Answer.
  • The view package contains all your activities: SplashActivity, MainActivity, QuestionActivity, and ResultActivity.

Now, build and run the app to verify that everything is working properly.

The Main screen.
The Main screen.

Cool! Now you are ready to start creating some Database Access Objects to manipulate the data.

Using DAOs to query your data

Database Access Objects are commonly known as DAOs. DAOs are objects that provide access to your app’s data, and they are what make Room so powerful since they abstract most of the complexity of communicating to the actual database. Using DAOs instead of query builders or direct queries makes it very easy to interact with your database. You avoid all the hardship of debugging query builders, if something breaks, and we all know how tricky SQL can be! They also provide a better separation of concerns to create a more structured application and improve its testability.

@Dao
interface QuizDao {
}
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(question: Question)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(answer: Answer)
@Query("DELETE FROM question")
fun clearQuestions()
@Delete
fun deleteQuestion(question: Question)
@Query("SELECT * FROM question ORDER BY question_id") // 1
fun getAllQuestions(): List<Question>

@Transaction // 2
@Query("SELECT * FROM question") // 3
fun getQuestionAndAllAnswers(): List<QuestionAndAllAnswers>
abstract fun quizDao(): QuizDao
@Database(
    entities = [(Question::class), (Answer::class)],
    version = 1
)
abstract class QuizDatabase : RoomDatabase() {

    abstract fun quizDao(): QuizDao
}

Creating a provider class

Now that your DAO methods are ready, you’ll create a provider class, that you will need later on, to prepopulate your database. Create a new class under the data package, name it QuestionInfoProvider and add the following method:

private fun initQuestionList(): MutableList<Question> {
  val questions = mutableListOf<Question>()
  questions.add(
      Question(
          1,
          "Which of the following languages is not commonly used to develop Android Apps")
  )
  questions.add(
      Question(
          2,
          "What is the meaning of life?")
  )
  return questions
}
private fun initAnswersList(): MutableList<Answer> {
  val answers = mutableListOf<Answer>()
  answers.add(Answer(
      1,
      1,
      true,
      "Java"
  ))
  answers.add(Answer(
      2,
      1,
      false,
      "Kotlin"
  ))
  answers.add(Answer(
      3,
      1,
      false,
      "Ruby"
  ))
  answers.add(Answer(
      4,
      2,
      true,
      "42"
  ))
  answers.add(Answer(
      5,
      2,
      false,
      "35"
  ))
  answers.add(Answer(
      6,
      2,
      false,
      "7"
  ))
  return answers
}
val questionList = initQuestionList()
val answerList = initAnswersList()
object QuestionInfoProvider { ...}
Verifying that the app is working fine.
Zicuzyecw psef ccu ohg al nekjimg reso.

Testing your database

Although your app’s UI isn’t working yet, you can still interact with your database by performing some tests such as adding or deleting questions to verify its functionality.

The androidTest package.
Hli ijktaulSest qeldemu.

@RunWith(AndroidJUnit4::class)
class QuizDaoTest { // 1
  @Rule
  @JvmField
  val rule: TestRule = InstantTaskExecutorRule() // 2

  private lateinit var database: QuizDatabase // 3
  private lateinit var quizDao: QuizDao // 4
}
@Before
fun setUp() {
  val context = InstrumentationRegistry.getInstrumentation().context // 1
  try {
    database = Room.inMemoryDatabaseBuilder(
        context, 
        QuizDatabase::class.java) //2
      .allowMainThreadQueries() //3
      .build()
  } catch (e: Exception) {
    Log.i(this.javaClass.simpleName, e.message ?: "") //4
  }
  quizDao = database.quizDao() //5
}
@Test
fun testInsertQuestion() {
  // 1
  val previousNumberOfQuestions = quizDao.getAllQuestions().size
  //2
  val question = Question(1, "What is your name?")
  quizDao.insert(question)
  //3
  val newNumberOfQuestions = quizDao.getAllQuestions().size
  //4 
  val changeInQuestions = newNumberOfQuestions - previousNumberOfQuestions
  // 5
  Assert.assertEquals(1, changeInQuestions)
}
@Test
fun testClearQuestions() {
  for (question in QuestionInfoProvider.questionList) {
    quizDao.insert(question)
  }
  Assert.assertTrue(quizDao.getAllQuestions().isNotEmpty())
  Log.d("testData", quizDao.getAllQuestions().toString())
  quizDao.clearQuestions()
  Assert.assertTrue(quizDao.getAllQuestions().isEmpty())
}
@After
fun tearDown() {
  database.close()
}
Running the Instrumenttion Test.
Zancibm vzu Iqdvheboznteur Kipf.

Key points

Where to go from here?

You now know how to create DAOs to interact with your database. You can download the final project by opening the attachment on this chapter, and if you want to learn more about DAOs in Room, you can explore the following resources:

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.