Chapters

Hide chapters

Saving Data on Android

First Edition · Android 10 · Kotlin 1.3 · AS 3.5

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

Using Firebase

Section 3: 11 chapters
Show chapters Hide chapters

8. The DAO Pattern
Written by Aldo Olivares

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

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

Now, you are going to learn how to retrieve, insert, delete and update data from your database using Database Access Objects.

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 the @Query annotation, 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 3.4 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: MainActivity, QuestionActivity and the ResultActivity.

Now Build and Run the app to verify that everything is working properly:

Cool! Now you are ready to start creating some Database Access Objects in order 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 questions")
fun clearQuestions()
@Delete
fun deleteQuestion(question: Question)
@Query("SELECT * FROM questions ORDER BY question_id") // 1
fun getAllQuestions(): List<Question>

@Transaction // 2
@Query("SELECT * FROM questions") // 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 will 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
}
var questionList = initQuestionList()
var answerList = initAnswersList()
object QuestionInfoProvider {
  
  var questionList = initQuestionList()
  var answerList = initAnswersList()

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

Testing your database

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

@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: 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 numberOfQuestions = quizDao.getAllQuestions().size
  // 4
  val numberOfNewQuestions = 
      numberOfQuestions - previousNumberOfQuestions
  // 5
  Assert.assertEquals(1, numberOfNewQuestions)
  // 6
  quizDao.clearQuestions()
  // 7
  Assert.assertEquals(0, quizDao.getAllQuestions().size)
}
@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()
}

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.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now