kotlin结合Room在实际项目中的运用
架构还是MVVM,DataBinding+ViewModel+LiveData的组合
效果:
1.首先添加Room依赖
添加kapt插件:
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
def room_version = "2.3.0"
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
2.创建数据库相关类
entity:
package com.aruba.flowapplyapplication.database.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
/**
* Created by aruba on 2021/9/20.
*/
@Entity
data class UserInfo(
@PrimaryKey val id: Int,
var userName: String,
var age: Int
)
Dao,之前我们需要使用异步任务操作Dao,kotlin则可以使用挂起函数,标识使用协程操作:
package com.aruba.flowapplyapplication.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.aruba.flowapplyapplication.database.entity.UserInfo
import kotlinx.coroutines.flow.Flow
/**
* Created by aruba on 2021/9/20.
*/
@Dao
interface UserInfoDao {
//id重复的替换
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(userInfo: UserInfo)
//返回Flow,由于Flow需要使用collect,该函数为挂起函数,所以不需要加suspend了
@Query("SELECT * FROM userinfo")
fun getUserInfoList(): Flow<List<UserInfo>>
}
Database:
package com.aruba.flowapplyapplication.database
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.aruba.flowapplyapplication.database.dao.UserInfoDao
import com.aruba.flowapplyapplication.database.entity.UserInfo
private const val DB_NAME: String = "my.db"
/**
* Created by aruba on 2021/9/20.
*/
@Database(entities = [UserInfo::class], version = 1, exportSchema = true)
abstract class MyDatabase : RoomDatabase() {
abstract fun getUserDao(): UserInfoDao
companion object {
private var instance: MyDatabase? = null
fun getInstance(): MyDatabase {
checkNotNull(instance) { "init has not been called" }
return instance as MyDatabase
}
fun init(context: Context) {
synchronized(this) {
instance ?: Room.databaseBuilder(
context,
MyDatabase::class.java, DB_NAME
).build().let { instance = it }
}
}
}
}
3.定义ViewModel
使用LiveData对三个EditText进行双向绑定
package com.aruba.flowapplyapplication.viewmodel
import android.view.View
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aruba.flowapplyapplication.database.MyDatabase
import com.aruba.flowapplyapplication.database.dao.UserInfoDao
import com.aruba.flowapplyapplication.database.entity.UserInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import androidx.databinding.ObservableField
/**
* Created by aruba on 2021/9/20.
*/
class UserInfoViewModel : ViewModel() {
val id = MutableLiveData<String>()
val name = MutableLiveData<String>()
val age = MutableLiveData<String>()
private val userInfoDao: UserInfoDao by lazy {
MyDatabase.getInstance().getUserDao()
}
fun insert(v: View) {
if (id.value == null || name.value == null || age.value == null) {
return
}
val userInfo = UserInfo(id.value!!.toInt(), name.value!!, age.value!!.toInt())
viewModelScope.launch(Dispatchers.IO) {
userInfoDao.insert(userInfo)
}
}
fun getUserInfo(): Flow<List<UserInfo>> {
return userInfoDao
.getUserInfoList()
.flowOn(Dispatchers.IO)
}
}
4.定义RecyclerViewAdapter
package com.aruba.flowapplyapplication.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.RecyclerView
import com.aruba.flowapplyapplication.R
import com.aruba.flowapplyapplication.database.entity.UserInfo
import com.aruba.flowapplyapplication.databinding.ItemUserinfoBinding
/**
* Created by aruba on 2021/9/20.
*/
class UserInfoAdapter() : RecyclerView.Adapter<UserInfoAdapter.MyViewHolder>() {
private var data = ArrayList<UserInfo>()
class MyViewHolder(val binding: ItemUserinfoBinding) : RecyclerView.ViewHolder(binding.root)
fun setData(data: List<UserInfo>) {
this.data.clear()
this.data.addAll(data)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val binding: ItemUserinfoBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.item_userinfo,
parent, false
)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.binding.userInfo = data[position]
}
override fun getItemCount(): Int {
return data.size
}
}
5.Fragment中实例化ViewModel,以及进行数据绑定等操作
package com.aruba.flowapplyapplication
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.aruba.flowapplyapplication.adapter.UserInfoAdapter
import com.aruba.flowapplyapplication.database.MyDatabase
import com.aruba.flowapplyapplication.databinding.FragmentRoomBinding
import com.aruba.flowapplyapplication.viewmodel.UserInfoViewModel
import kotlinx.coroutines.flow.collect
class RoomFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//初始化数据库
MyDatabase.init(requireContext())
val inflate = DataBindingUtil.inflate<FragmentRoomBinding>(
layoutInflater,
R.layout.fragment_room,
container,
false
)
//实例化ViewModel
val userInfoViewModel = ViewModelProvider(
this,
ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
).get(UserInfoViewModel::class.java)
inflate.userInfoViewModel = userInfoViewModel
inflate.recyclerview.adapter = UserInfoAdapter()
inflate.recyclerview.layoutManager = LinearLayoutManager(context)
inflate.lifecycleOwner = viewLifecycleOwner
//开启协程对数据库的表进行监听
lifecycleScope.launchWhenCreated {
//每当UserInfo表发生变化,Flow都会把UserInfo列表发射出去,那么我们
//在collect中就可以获取到
userInfoViewModel.getUserInfo().collect {
(inflate.recyclerview.adapter as UserInfoAdapter).setData(it)
}
}
return inflate.root
}
}