看下应用效果
点击addUser,就增加一条数据,同步到下面的RecyclerView。
界面很简单,没什么可讲的
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dip">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et_user_id"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="USER ID"/>
<EditText
android:id="@+id/et_first_name"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="FIRST NAME"/>
<EditText
android:id="@+id/et_last_name"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="LAST NAME"/>
</LinearLayout>
<Button
android:id="@+id/btn_add_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ADD USER"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</LinearLayout>
上面三个输入框,中间一个按钮,下面一个RecyclerView
看下AppDatabase
package com.dongnaoedu.flowpractice.db
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import kotlin.coroutines.Continuation
/**
*
* @author ningchuanqi
* @version V1.0
*/
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
Room.databaseBuilder(context, AppDatabase::class.java, "flow_practice.db")
.build().also { instance = it }
}
}
}
}
user实体
package com.dongnaoedu.flowpractice.db
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
/**
*
* @author ningchuanqi
* @version V1.0
*/
@Entity
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "first_name") val firstName: String,
@ColumnInfo(name = "last_name") val lastName: String
)
Dao类
package com.dongnaoedu.flowpractice.db
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import kotlinx.coroutines.flow.Flow
/**
*
* @author ningchuanqi
* @version V1.0
*/
@Dao
interface UserDao {
//冲突策略,ID相同替换
//插入需要关键字suspend,以支持协程
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User)
//查询所有用户,返回一个Flow,查询函数不需要加suspend
//如果是返回livedata,也不需要suspend
@Query("SELECT * FROM user")
fun getAll(): Flow<List<User>>
}
通过ViewModel访问数据库
package com.dongnaoedu.flowpractice.viewmodel
import android.app.Application
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.dongnaoedu.flowpractice.db.AppDatabase
import com.dongnaoedu.flowpractice.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
/**
继承AndroidViewModel,可以拿到上下文。
*/
class UserViewModel(app: Application) : AndroidViewModel(app) {
fun insert(uid: String, firstName: String, lastName: String) {
viewModelScope.launch {
//insert是个挂起函数,要在协程里执行
AppDatabase.getInstance(getApplication())
.userDao()
.insert(User(uid.toInt(), firstName, lastName))
Log.d("ning", "insert user:$uid")
}
}
fun getAll(): Flow<List<User>> {
return AppDatabase.getInstance(getApplication())
.userDao()
.getAll()
//捕捉异常
.catch { e -> e.printStackTrace() }
//指定调度器,在IO调度器上查询
.flowOn(Dispatchers.IO)
}
}
看下Fragment界面,首先创建RecyclerView的是配置
package com.dongnaoedu.flowpractice.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.dongnaoedu.flowpractice.databinding.ItemUserBinding
import com.dongnaoedu.flowpractice.db.User
/**
*
* @author ningchuanqi
* @version V1.0
*/
class UserAdapter(private val context: Context) : RecyclerView.Adapter<BindingViewHolder>() {
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): BindingViewHolder {
//ItemUserBinding自动生成的
val binding = ItemUserBinding.inflate(LayoutInflater.from(context), parent, false)
return BindingViewHolder(binding)
}
override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
//取出数据
val item = data[position]
val binding = holder.binding as ItemUserBinding
binding.text.text = "${item.uid}, ${item.firstName}, ${item.lastName}"
}
override fun getItemCount() = data.size
}
package com.dongnaoedu.flowpractice.adapter
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
/**
*
* @author ningchuanqi
* @version V1.0
*/
class BindingViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {
}
看下Fragment
package com.dongnaoedu.flowpractice.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.dongnaoedu.flowpractice.R
import com.dongnaoedu.flowpractice.adapter.UserAdapter
import com.dongnaoedu.flowpractice.databinding.FragmentDownloadBinding
import com.dongnaoedu.flowpractice.databinding.FragmentUserBinding
import com.dongnaoedu.flowpractice.viewmodel.UserViewModel
import kotlinx.coroutines.flow.collect
class UserFragment : Fragment() {
//拿到ViewModel
private val viewModel by viewModels<UserViewModel>()
private val mBinding: FragmentUserBinding by lazy {
FragmentUserBinding.inflate(layoutInflater)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return mBinding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mBinding.apply {
btnAddUser.setOnClickListener {
viewModel.insert(
etUserId.text.toString(),
etFirstName.text.toString(),
etLastName.text.toString()
)
}
}
//UserAdapter传入的context可空,使用空安全操作符+let
context?.let {
val adapter = UserAdapter(it)
mBinding.recyclerView.adapter = adapter
//起一个协程,从flow里收集元素
lifecycleScope.launchWhenCreated {
viewModel.getAll().collect { value ->
adapter.setData(value)//数据给到适配器,刷新视图
}
}
}
}
}