0% found this document useful (0 votes)
81 views11 pages

Room Database Builder for Codelab7

The document contains XML layout files and Kotlin code for an Android app that allows users to add words to a database using a RecyclerView. The layout files define the user interface for listing and adding words. The Kotlin code includes activities for the main screen and adding words, a Word data model, a WordDao for database access, and an adapter for the RecyclerView.

Uploaded by

Walter Peralta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
81 views11 pages

Room Database Builder for Codelab7

The document contains XML layout files and Kotlin code for an Android app that allows users to add words to a database using a RecyclerView. The layout files define the user interface for listing and adding words. The Kotlin code includes activities for the main screen and adding words, a Word data model, a WordDao for database access, and an adapter for the RecyclerView.

Uploaded by

Walter Peralta
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 11

Peralta, Walter V.

CC17 CITCS 3B-2


XML files
[Link]
<?xml version="1.0" encoding="utf-8"?>

<[Link]
xmlns:android="[Link]
xmlns:app="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<[Link]
android:id="@+id/recyclerview"
android:layout_width="0dp"
android:layout_height="0dp"
tools:listitem="@layout/recyclerview_item"
android:padding="@dimen/big_padding"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<[Link]
android:id="@+id/fab"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="@string/add_word"
android:src="@drawable/ic_add_black_24dp"/>

</[Link]>

activity_new_word.xml
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="[Link]
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<EditText
android:id="@+id/edit_word"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/min_height"
android:fontFamily="sans-serif-light"
android:hint="@string/hint_word"
android:inputType="textAutoComplete"
android:layout_margin="@dimen/big_padding"
android:textSize="18sp" />

<Button
android:id="@+id/button_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:text="@string/button_save"
android:layout_margin="@dimen/big_padding"
android:textColor="@color/buttonLabel" />

</LinearLayout>
content_main.xml
<?xml version="1.0" encoding="utf-8"?>

<[Link]
xmlns:android="[Link]
xmlns:app="[Link]
xmlns:tools="[Link]
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="[Link]"
tools:showIn="@layout/activity_main">

<[Link]
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/recyclerview_item"/>

</[Link]>
recyclerviewer_item.xml
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="[Link]
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:id="@+id/textView"
style="@style/word_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_light" />
</LinearLayout>
[Link]
<?xml version="1.0" encoding="utf-8"?>

<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="buttonLabel">#FFFFFF</color>
</resources>
[Link]

<resources>
<dimen name="small_padding">8dp</dimen>
<dimen name="big_padding">16dp</dimen>
<dimen name="min_height">48dp</dimen>
</resources>
[Link]
<resources>
<string name="app_name">RoomWordsSample</string>
<string name="action_settings">Settings</string>
<string name="hint_word">Word…</string>
<string name="button_save">Save</string>
<string name="empty_not_saved">Word not saved because it is empty.</string>
<string name="add_word">Add word</string>
</resources>
[Link]
<resources>

<!-- Base application theme. -->


<style name="AppTheme" parent="[Link]">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

<!-- The default font for RecyclerView items is too small.


The margin is a simple delimiter between the words. -->
<style name="word_title">
<item name="android:layout_marginBottom">8dp</item>
<item name="android:paddingLeft">8dp</item>
<item name="android:background">@android:color/holo_orange_light</item>
<item
name="android:textAppearance">@android:style/[Link]</item>
</style>
</resources>
Kotlin codes
[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class MainActivity : AppCompatActivity() {

private val newWordActivityRequestCode = 1


private val wordViewModel: WordViewModel by viewModels {
WordViewModelFactory((application as WordsApplication).repository)
}

override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_main)

val recyclerView = findViewById<RecyclerView>([Link])


val adapter = WordListAdapter()
[Link] = adapter
[Link] = LinearLayoutManager(this)
[Link](owner = this) { words ->

[Link] { [Link](it) }
}

val fab = findViewById<FloatingActionButton>([Link])


[Link] {
val intent = Intent(this@MainActivity, NewWordActivity::[Link])
startActivityForResult(intent, newWordActivityRequestCode)
}
}

override fun onActivityResult(requestCode: Int, resultCode: Int, intentData:


Intent?) {
[Link](requestCode, resultCode, intentData)

if (requestCode == newWordActivityRequestCode && resultCode ==


Activity.RESULT_OK) {
intentData?.getStringExtra(NewWordActivity.EXTRA_REPLY)?.let { reply ->
val word = Word(reply)
[Link](word)
}
} else {
[Link](
applicationContext,
[Link].empty_not_saved,
Toast.LENGTH_LONG
).show()
}
}
}
[Link]

package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class NewWordActivity : AppCompatActivity() {

public override fun onCreate(savedInstanceState: Bundle?) {


[Link](savedInstanceState)
setContentView([Link].activity_new_word)
val editWordView = findViewById<EditText>([Link].edit_word)

val button = findViewById<Button>([Link].button_save)


[Link] {
val replyIntent = Intent()
if ([Link]([Link])) {
setResult(Activity.RESULT_CANCELED, replyIntent)
} else {
val word = [Link]()
[Link](EXTRA_REPLY, word)
setResult(Activity.RESULT_OK, replyIntent)
}
finish()
}
}

companion object {
const val EXTRA_REPLY = "[Link]"
}
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]

@Entity(tableName = "word_table")
data class Word(@PrimaryKey @ColumnInfo(name = "word") val word: String)

[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

@Dao
interface WordDao {

// The flow always holds/caches latest version of data. Notifies its observers
when the
// data has changed.
@Query("SELECT * FROM word_table ORDER BY word ASC")
fun getAlphabetizedWords(): Flow<List<Word>>

@Insert(onConflict = [Link])
suspend fun insert(word: Word)

@Query("DELETE FROM word_table")


suspend fun deleteAll()
}
[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class WordListAdapter : ListAdapter<Word, WordViewHolder>(WORDS_COMPARATOR) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WordViewHolder


{
return [Link](parent)
}
override fun onBindViewHolder(holder: WordViewHolder, position: Int) {
val current = getItem(position)
[Link]([Link])
}

class WordViewHolder(itemView: View) : [Link](itemView) {


private val wordItemView: TextView = [Link]([Link])

fun bind(text: String?) {


[Link] = text
}

companion object {
fun create(parent: ViewGroup): WordViewHolder {
val view: View = [Link]([Link])
.inflate([Link].recyclerview_item, parent, false)
return WordViewHolder(view)
}
}
}

companion object {
private val WORDS_COMPARATOR = object : [Link]<Word>() {
override fun areItemsTheSame(oldItem: Word, newItem: Word): Boolean {
return oldItem === newItem
}

override fun areContentsTheSame(oldItem: Word, newItem: Word): Boolean {


return [Link] == [Link]
}
}
}
}
[Link]
package [Link]

import [Link]
import [Link]

class WordRepository(private val wordDao: WordDao) {

val allWords: Flow<List<Word>> = [Link]()

@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun insert(word: Word) {
[Link](word)
}
}
[Link]
package [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

@Database(entities = [Word::class], version = 1)


abstract class WordRoomDatabase : RoomDatabase() {

abstract fun wordDao(): WordDao

companion object {
@Volatile
private var INSTANCE: WordRoomDatabase? = null

fun getDatabase(
context: Context,
scope: CoroutineScope
): WordRoomDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = [Link](
[Link],
WordRoomDatabase::[Link],
"word_database"
)

.fallbackToDestructiveMigration()
.addCallback(WordDatabaseCallback(scope))
.build()
INSTANCE = instance

instance
}
}

private class WordDatabaseCallback(


private val scope: CoroutineScope
) : [Link]() {

override fun onCreate(db: SupportSQLiteDatabase) {


[Link](db)
// If you want to keep the data through app restarts,
// comment out the following line.
INSTANCE?.let { database ->
[Link]([Link]) {
populateDatabase([Link]())
}
}
}
}

suspend fun populateDatabase(wordDao: WordDao) {


// Start the app with a clean database every time.
// Not needed if you only populate on creation.
[Link]()

var word = Word("Hello")


[Link](word)
word = Word("World!")
[Link](word)
}
}
}
[Link]
package [Link]

import [Link]
import [Link]
import [Link]

class WordsApplication : Application() {

val applicationScope = CoroutineScope(SupervisorJob())

val database by lazy { [Link](this, applicationScope) }


val repository by lazy { WordRepository([Link]()) }
}
[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

class WordViewModel(private val repository: WordRepository) : ViewModel() {


val allWords: LiveData<List<Word>> = [Link]()

fun insert(word: Word) = [Link] {


[Link](word)
}
}

class WordViewModelFactory(private val repository: WordRepository) :


[Link] {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if ([Link](WordViewModel::[Link])) {
@Suppress("UNCHECKED_CAST")
return WordViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
[Link]
package [Link]

import [Link]
import [Link]
import [Link]
import [Link].AndroidJUnit4
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]
import [Link]

@RunWith(AndroidJUnit4::class)
class WordDaoTest {

private lateinit var wordDao: WordDao


private lateinit var db: WordRoomDatabase

@Before
fun createDb() {
val context: Context = [Link]()
// Using an in-memory database because the information stored here disappears
when the
// process is killed.
db = [Link](context, WordRoomDatabase::[Link])
// Allowing main thread queries, just for testing.
.allowMainThreadQueries()
.build()
wordDao = [Link]()
}

@After
@Throws(IOException::class)
fun closeDb() {
[Link]()
}

@Test
@Throws(Exception::class)
fun insertAndGetWord() = runBlocking {
val word = Word("word")
[Link](word)
val allWords = [Link]().first()
assertEquals(allWords[0].word, [Link])
}

@Test
@Throws(Exception::class)
fun getAllWords() = runBlocking {
val word = Word("aaa")
[Link](word)
val word2 = Word("bbb")
[Link](word2)
val allWords = [Link]().first()
assertEquals(allWords[0].word, [Link])
assertEquals(allWords[1].word, [Link])
}

@Test
@Throws(Exception::class)
fun deleteAll() = runBlocking {
val word = Word("word")
[Link](word)
val word2 = Word("word2")
[Link](word2)
[Link]()
val allWords = [Link]().first()
assertTrue([Link]())
}
}

Output

You might also like