Open menu with table of contents Android Assignment 04
Logo of Stuttgart Media University for light theme Logo of Stuttgart Media University for dark theme
Android Development

Android Assignment 04

Introduction to Database with Room

Stuttgart Media University

Please conduct the following tasks alone. For implementation details you can refer to the lecture slides or the Android developer website. Please do not hesitate to ask me or the tutor if you have any questions.

1 Tasks

  • Reuse your assignment3 code and copy it to assignment4 folder.
  • In your app gradle, increase compileSdk to 34 (should be 30 since Room dependency gives us errors with compileSdk 30)
  • Remove your MovieDb class from Assignment3.
  • Implement Room library to permanently save selected movies in database accross app starts
  • Verify that selected movies are shown on app start in MainActivity / Fragment / RecyclerView

2 Movie Data

Use this data to fill out your rows:

title year actor
Dr. No 1962 Sean Connery
From Russia with Love 1963 Sean Connery
Goldfinger 1964 Sean Connery
Thunderball 1965 Sean Connery
You Only Live Twice 1967 Sean Connery

3 Espresso Test

package de.hdmstuttgart.movietracker

import android.view.View
import androidx.recyclerview.widget.RecyclerView
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions
import androidx.test.espresso.core.internal.deps.guava.base.Preconditions
import androidx.test.espresso.matcher.BoundedMatcher
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.junit.Rule
import org.junit.Test


class Assignment4Test {

    @get:Rule
    var activityScenarioRule = ActivityScenarioRule(
        MainActivity::class.java
    )

    @Test
    fun assignment4Test() {
        onView(withId(R.id.searchBtn))
            .perform(click())

        onView(withId(R.id.searchMovieTitleEditText))
            .perform(replaceText("Gold"), closeSoftKeyboard())

        onView(withId(R.id.searchMovieTitleButton))
            .perform(click())

        onView(withId(R.id.searchRecyclerView))
            .check(matches(atPosition(0, hasDescendant(withText("Goldfinger")))))

        onView(withId(R.id.searchRecyclerView))
            .perform(
                RecyclerViewActions.actionOnItemAtPosition<MovieAdapter.ViewHolder>(
                    0,
                    click()
                )
            )

        onView(withId(R.id.homeRecyclerView))
            .check(matches(atPosition(0, hasDescendant(withText("Goldfinger")))))

        onView(withId(R.id.searchBtn))
            .perform(click())

        onView(withId(R.id.searchMovieTitleEditText))
            .perform(replaceText("uss"), closeSoftKeyboard())

        onView(withId(R.id.searchMovieTitleButton))
            .perform(click())

        onView(withId(R.id.searchRecyclerView))
            .check(matches(atPosition(0, hasDescendant(withText("From Russia with Love")))))

        onView(withId(R.id.searchRecyclerView))
            .perform(
                RecyclerViewActions.actionOnItemAtPosition<MovieAdapter.ViewHolder>(
                    0,
                    click()
                )
            )

        onView(withId(R.id.homeRecyclerView))
            .check(matches(atPosition(1, hasDescendant(withText("From Russia with Love")))))

        onView(withId(R.id.homeRecyclerView))
            .perform(
                RecyclerViewActions.actionOnItemAtPosition<MovieAdapter.ViewHolder>(
                    0,
                    click()
                )
            )

        onView(withId(R.id.homeRecyclerView))
            .check(matches(atPosition(0, hasDescendant(withText("From Russia with Love")))))

        activityScenarioRule.scenario.close()

        ActivityScenario.launch(MainActivity::class.java)

        onView(withId(R.id.homeRecyclerView))
            .check(matches(atPosition(0, hasDescendant(withText("From Russia with Love")))))
    }

    companion object {
        fun atPosition(
            position: Int,
            itemMatcher: Matcher<View?>
        ): BoundedMatcher<View?, RecyclerView> {
            Preconditions.checkNotNull(itemMatcher)
            return object : BoundedMatcher<View?, RecyclerView>(RecyclerView::class.java) {
                override fun describeTo(description: Description) {
                    description.appendText("has item at position $position: ")
                    itemMatcher.describeTo(description)
                }

                override fun matchesSafely(view: RecyclerView): Boolean {
                    val viewHolder = view.findViewHolderForAdapterPosition(position)
                        ?: // has no item on such position
                        return false
                    return itemMatcher.matches(viewHolder.itemView)
                }
            }
        }
    }
}

4 Gradle Dependencies

dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
    implementation("androidx.appcompat:appcompat:1.6.1")
    implementation("com.google.android.material:material:1.9.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    implementation("androidx.recyclerview:recyclerview:1.3.1")
    implementation("androidx.test.espresso:espresso-contrib:3.5.1")
    testImplementation("junit:junit:4.13.2")
    androidTestImplementation("androidx.test.ext:junit:1.1.5")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
    implementation("androidx.room:room-runtime:2.5.2")
    implementation("androidx.room:room-ktx:2.5.2")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
    ksp("androidx.room:room-compiler:2.5.2")
}