Room

build.gradle(app) 設定

plugin

1
2
3
plugins {
    id 'kotlin-kapt'  // 確保有這行
}

implementation

記得一定要加上kapt

1
2
3
4
    def room_version = "2.8.2"
    implementation "androidx.room:room-runtime:$room_version"
    implementation "androidx.room:room-ktx:$room_version"
    kapt "androidx.room:room-compiler:$room_version"   // ← 必須加這行!

Room建立步驟

MyDatabase 建立資料庫

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.example.coroutine.db
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class MyDatabase: RoomDatabase() {
  abstract fun userDao(): UserDao
  companion object {
    private var instance: MyDatabase? = null
    fun getInstance(context: Context): MyDatabase {
      return instance ?: synchronized(this) {
        val newInstance = Room.databaseBuilder(context, MyDatabase::class.java,"user.db").build()
        instance = newInstance
        newInstance
      }
    }
  }
}

User 表格

有二個欄位,分別是uid與name。

1
2
3
4
5
6
7
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "user")
data class User (
  @PrimaryKey val uid: Int,
  @ColumnInfo(name = "name") val name: String)

UserDao 資料庫操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow

@Dao
interface UserDao {
  @Insert(onConflict = OnConflictStrategy.REPLACE)
  suspend fun insert(user: User)

  @Query("SELECT * FROM user")
  fun getAll(): Flow<List<User>>
}

Activity 測試

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.example.coroutine.activity

import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.coroutine.R
import com.example.coroutine.db.MyDatabase
import com.example.coroutine.db.User
import kotlinx.coroutines.launch

class MainActivity18 : AppCompatActivity() {
  private val db by lazy { MyDatabase.getInstance(this) }
  private val userDao by lazy { db.userDao() }
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val submit = findViewById<Button>(R.id.button)
    val textv = findViewById<TextView>(R.id.textView)
    submit.setOnClickListener {
      lifecycleScope.launch {
        userDao.insert(User(3, "Bob"))
      }
    }
    lifecycleScope.launch {
      userDao.getAll().collect { user ->
        textv.text = "$user"
      }
    }
  }
}

結合viewmodel flow adapter

viewmodel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.example.coroutine.db.MyDatabase
import com.example.coroutine.db.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch

class UserViewModel(app: Application) : AndroidViewModel(app) {
  fun insert(uid: String, name: String) {
    viewModelScope.launch {
      MyDatabase.getInstance(getApplication())
        .userDao().insert(User(uid.toInt(), name))
    }
  }
  fun getAll(): Flow<List<User>> {
    return MyDatabase.getInstance(getApplication())
      .userDao()
      .getAll()
      .catch { e -> e.printStackTrace() }
      .flowOn(Dispatchers.IO)
  }
}

adapter

adapter 與 veiwholder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import com.example.coroutine.adapter.UserAdapter.UserItemViewHold
import com.example.coroutine.databinding.UserItemBinding
import com.example.coroutine.db.User

class UserAdapter(private val context: Context) : RecyclerView.Adapter<UserItemViewHold>() {
  inner class UserItemViewHold(val binding: ViewBinding) :
    RecyclerView.ViewHolder(binding.root) {}

  private val data = ArrayList<User>()
  fun setData(data: List<User>) {
    this.data.clear()
    this.data.addAll(data)
    notifyDataSetChanged()
  }

  override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int
  ): UserItemViewHold {
    val binding = UserItemBinding.inflate(LayoutInflater.from(context), parent, false)
    return UserItemViewHold(binding)
  }

  override fun onBindViewHolder(
    holder: UserItemViewHold,
    position: Int
  ) {
    val item = data[position]
    val binding = holder.binding as UserItemBinding
    binding.nameTv.text = "${item.uid} , ${item.name}"
  }

  override fun getItemCount(): Int = data.size
}

xml

user_item.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/name_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Activity

Activity程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.coroutine.adapter.UserAdapter
import com.example.coroutine.databinding.ActivityDbBinding
import com.example.coroutine.model.UserViewModel
import kotlinx.coroutines.launch
import androidx.activity.viewModels
import androidx.recyclerview.widget.LinearLayoutManager

class MainActivity17 : AppCompatActivity() {
  private val viewModel by viewModels<UserViewModel>()
  private lateinit var binding : ActivityDbBinding
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityDbBinding.inflate(layoutInflater)

    setContentView(binding.root)
    val addBtn = binding.addBtn
    val uidEdit = binding.uid
    val nameEdit = binding.name
    addBtn.setOnClickListener {
      viewModel.insert(uidEdit.text.toString(), nameEdit.text.toString())
    }
    val adapter = UserAdapter(this@MainActivity17)
    binding.dbRecycleview.layoutManager = LinearLayoutManager(this)
    binding.dbRecycleview.adapter = adapter
    lifecycleScope.launch {
      viewModel.getAll().collect { value ->
        adapter.setData(value)
      }
    }
  }
}

xml

activity_db.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="40dp"
        android:layout_marginTop="128dp"
        android:text="uid"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/uid"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="48dp"
        android:layout_marginTop="104dp"
        android:ems="10"
        android:inputType="text"
        android:text=""
        app:layout_constraintStart_toEndOf="@+id/textView3"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="68dp"
        android:text="name"
        app:layout_constraintTop_toBottomOf="@+id/textView3"
        tools:layout_editor_absoluteX="40dp" />

    <EditText
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="52dp"
        android:ems="10"
        android:inputType="text"
        android:text="Name"
        app:layout_constraintTop_toBottomOf="@+id/uid"
        tools:layout_editor_absoluteX="107dp" />

    <Button
        android:id="@+id/addBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:text="Button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/name" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/db_recycleview"
        android:layout_width="409dp"
        android:layout_height="406dp"
        android:layout_marginStart="1dp"
        android:layout_marginEnd="1dp"
        android:layout_marginBottom="2dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/addBtn" />

</androidx.constraintlayout.widget.ConstraintLayout>

results matching ""

    No results matching ""