
架构图如上所示:Dao层操作数据库,dataBase 实例 需要基础 RoomDataBase 执行一下 数据库的一下操作,viewModel 层 提供dataBase
使用viewmodel层提供的database 去修改操作视图,Adapter 加载结合:AsyncListDiffer
开发步骤:
1.按照Google developer开发文档将Room 接入到项目中:https://developer.android.com/training/data-storage/room
Room 包含三个主要组件:
数据库类为应用提供与该数据库关联的 DAO 的实例。反过来,应用可以使用 DAO 从数据库中检索数据,作为关联的数据实体对象的实例。此外,应用还可以使用定义的数据实体更新相应表中的行,或者创建新行供插入。

- plugins {
- id 'com.android.application'
- id 'org.jetbrains.kotlin.android'
- id 'kotlin-kapt'
- }
- implementation("androidx.room:room-runtime:2.4.3")
- annotationProcessor("androidx.room:room-compiler:2.4.3")
- kapt("androidx.room:room-compiler:2.4.3")
2.定义数据实体
- @Entity
- data class User(
-
- @PrimaryKey
- var uid: Int,
-
- @ColumnInfo(name = "first_name")
- var firstName: String?,
-
- @ColumnInfo(name = "last_name")
- var lastName: String?
- ) {
-
- override fun equals(any: Any?): Boolean {
- if (any == null) {
- return false
- }
- val other: User = any as User
- return ((uid == other.uid && (firstName == other.firstName) && (lastName == other.lastName)))
- }
- }
3.数据访问对象Dao:
- @Dao
- interface UserDao {
-
- @Query("SELECT * FROM user")
- fun getAll(): LiveData
>? -
- @Query("SELECT * FROM user")
- fun getAll2(): MutableList
? -
- @Query("SELECT * FROM user WHERE uid IN (:userIds)")
- fun loadAllByIds(userIds: IntArray): List
-
- @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1")
- fun findByName(first: String, last: String): User
-
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insertOneUser(users: User)
-
- @Insert(onConflict = OnConflictStrategy.REPLACE)
- fun insertUserList(list: List<User>)
-
- @Delete
- fun delete(user: User)
-
- @Query("SELECT * FROM user ORDER BY last_name ASC")
- fun usersByLastName(): LiveData
>?
-
- }
注意数据访问对象Dao在插入的时候注意添加下:onConflict = OnConflictStrategy.REPLACE 意思是插入或者更新:insert or update
4.定义数据库:
AppDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点。数据库类必须满足以下条件:
- @Database(entities = [User::class], version = 1, exportSchema = false)
- abstract class AppDatabase : RoomDatabase() {
-
- abstract fun userDao(): UserDao
-
- companion object {
- @Volatile
- private var INSTANCE: AppDatabase? = null
-
- fun getInstance(): AppDatabase {
- synchronized(this) {
- var instance = INSTANCE
- if (instance == null) {
- instance = Room.databaseBuilder(MyApplication.instance(), AppDatabase::class.java, "my-database-name")
- .allowMainThreadQueries()
- .build()
- INSTANCE = instance
- }
- return instance
- }
- }
- }
- }
这里定义了一个AppDatabase单例,可以在全局中时候 AppDatabase实例
5.定义:ViewModel
- class MyViewModel : ViewModel() {
-
- fun getUsersList(): LiveData
>? { - return AppDatabase.getInstance().userDao().getAll()
- }
- }
6.Activity中添加 viewModel的:observe:
- viewModel.getUsersList()?.observe(this) {
- //获取到db 的数据后,开始显示到View上
- }
7.创建Adapter ,这里的Adapter 结合了:AsyncListDiffer:https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer
- public class UserAdapter extends RecyclerView.Adapter
{ -
- private final AsyncListDiffer
mDiffer = new AsyncListDiffer(this, DIFF_CALLBACK); -
- @Override
- public int getItemCount() {
- int size = mDiffer.getCurrentList().size();
- return size;
- }
-
- public void submitList(List
list) { - mDiffer.submitList(list);
- }
-
- @NonNull
- @Override
- public UserViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
- return new UserViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_user_adapter, viewGroup, false));
- }
-
- @Override
- public void onBindViewHolder(UserViewHolder holder, int position) {
- User user = mDiffer.getCurrentList().get(position);
- holder.bindView(user, position);
- }
-
- public class UserViewHolder extends RecyclerView.ViewHolder {
-
- TextView mIdView;
- TextView mFirstNameView;
- TextView mLastNameView;
-
- public UserViewHolder(@NonNull View itemView) {
- super(itemView);
- mIdView = itemView.findViewById(R.id.tv_id);
- mFirstNameView = itemView.findViewById(R.id.tv_first_name);
- mLastNameView = itemView.findViewById(R.id.tv_last_name);
- }
-
- public void bindView(User user, int position) {
- mIdView.setText("Id:" + user.getUid());
- mFirstNameView.setText(user.getFirstName());
- mLastNameView.setText(user.getLastName());
- }
- }
-
-
- public static final DiffUtil.ItemCallback
DIFF_CALLBACK = new DiffUtil.ItemCallback() { - @Override
- public boolean areItemsTheSame(
- @NonNull User oldUser, @NonNull User newUser) {
- // User properties may have changed if reloaded from the DB, but ID is fixed
- return oldUser.getUid() == newUser.getUid();
- }
-
- @Override
- public boolean areContentsTheSame(@NonNull User oldUser, @NonNull User newUser) {
- // NOTE: if you use equals, your object must properly override Object#equals()
- // Incorrectly returning false here will result in too many animations.
- return oldUser.equals(newUser);
- }
- };
- }
8.接下来就要实现数据的增删改查,同步显示在View上了:
插入数据:insert
- mBinding.btnAddView.setOnClickListener {
- mCoroutineScope.launch {
- val localUserList = AppDatabase.getInstance().userDao().getAll2()
- val count = localUserList?.size ?: 0
- val targetCount = count + 1
- val user = User(targetCount, "FirstName:" + targetCount, "LastName:" + targetCount)
- AppDatabase.getInstance().userDao().insertOneUser(user)
- }
- }
更新数据:update
- mBinding.btnEditView.setOnClickListener {
- mCoroutineScope.launch {
- val localUserList = AppDatabase.getInstance().userDao().getAll2()
- if (localUserList?.isNullOrEmpty() == true) {
- return@launch
- }
- localUserList?.forEach {
- it.firstName = it.firstName + "A"
- it.lastName = it.lastName + "B"
- }
-
- localUserList?.let {
- AppDatabase.getInstance().userDao().insertUserList(it)
- }
- }
- }
删除数据:delete:
- mBinding.btnDeleteView.setOnClickListener {
- mCoroutineScope.launch {
- val localUserList = AppDatabase.getInstance().userDao().getAll2()
- localUserList?.let {
- val user = it?.get(it.size - 1)
- if (user != null) {
- AppDatabase.getInstance().userDao().delete(user)
- }
- }
- }
- }
到目前为止就已经实现了:数据库的增删改查,同步显示到View 上:这样Room,ViewModel, AsyncListDiffer 结合在了一起
Demo地址:GitHub - JasonZhangHG/DiffUtilDemo: Room DB + ViewModel + AsyncListDiffer