Room+ViewModel+AsyncListDiffer【android JetPack】

 架构图如上所示:Dao层操作数据库,dataBase 实例 需要基础 RoomDataBase 执行一下 数据库的一下操作,viewModel 层 提供dataBase

使用viewmodel层提供的database 去修改操作视图,Adapter 加载结合:AsyncListDiffer

开发步骤:

1.按照Google developer开发文档将Room 接入到项目中:https://developer.android.com/training/data-storage/room

主要组件

Room 包含三个主要组件:

  • 数据库类,用于保存数据库并作为应用持久性数据底层连接的主要访问点。
  • 数据实体,用于表示应用的数据库中的表。
  • 数据访问对象 (DAO),提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。

数据库类为应用提供与该数据库关联的 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<MutableList<User>>?

    @Query("SELECT * FROM user")
    fun getAll2(): MutableList<User>?

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    fun loadAllByIds(userIds: IntArray): List<User>

    @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<List<User>>?

}

注意数据访问对象Dao在插入的时候注意添加下:onConflict = OnConflictStrategy.REPLACE 意思是插入或者更新:insert or update

4.定义数据库:

 AppDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点。数据库类必须满足以下条件:

  • 该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
  • 该类必须是一个抽象类,用于扩展 RoomDatabase
  • 对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
@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<MutableList<User>>? {
        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<UserAdapter.UserViewHolder> {

    private final AsyncListDiffer<User> mDiffer = new AsyncListDiffer(this, DIFF_CALLBACK);

    @Override
    public int getItemCount() {
        int size = mDiffer.getCurrentList().size();
        return size;
    }

    public void submitList(List<User> 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<User> DIFF_CALLBACK = new DiffUtil.ItemCallback<User>() {
        @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

猜你喜欢

转载自blog.csdn.net/Jason_HD/article/details/127110754