• 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 从数据库中检索数据,作为关联的数据实体对象的实例。此外,应用还可以使用定义的数据实体更新相应表中的行,或者创建新行供插入。

     

    1. plugins {
    2. id 'com.android.application'
    3. id 'org.jetbrains.kotlin.android'
    4. id 'kotlin-kapt'
    5. }
    1. implementation("androidx.room:room-runtime:2.4.3")
    2. annotationProcessor("androidx.room:room-compiler:2.4.3")
    3. kapt("androidx.room:room-compiler:2.4.3")

    2.定义数据实体

    1. @Entity
    2. data class User(
    3. @PrimaryKey
    4. var uid: Int,
    5. @ColumnInfo(name = "first_name")
    6. var firstName: String?,
    7. @ColumnInfo(name = "last_name")
    8. var lastName: String?
    9. ) {
    10. override fun equals(any: Any?): Boolean {
    11. if (any == null) {
    12. return false
    13. }
    14. val other: User = any as User
    15. return ((uid == other.uid && (firstName == other.firstName) && (lastName == other.lastName)))
    16. }
    17. }

    3.数据访问对象Dao:

    1. @Dao
    2. interface UserDao {
    3. @Query("SELECT * FROM user")
    4. fun getAll(): LiveData>?
    5. @Query("SELECT * FROM user")
    6. fun getAll2(): MutableList?
    7. @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    8. fun loadAllByIds(userIds: IntArray): List
    9. @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1")
    10. fun findByName(first: String, last: String): User
    11. @Insert(onConflict = OnConflictStrategy.REPLACE)
    12. fun insertOneUser(users: User)
    13. @Insert(onConflict = OnConflictStrategy.REPLACE)
    14. fun insertUserList(list: List<User>)
    15. @Delete
    16. fun delete(user: User)
    17. @Query("SELECT * FROM user ORDER BY last_name ASC")
    18. fun usersByLastName(): LiveData>?
    19. }

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

    4.定义数据库:

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

    • 该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
    • 该类必须是一个抽象类,用于扩展 RoomDatabase
    • 对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。
    1. @Database(entities = [User::class], version = 1, exportSchema = false)
    2. abstract class AppDatabase : RoomDatabase() {
    3. abstract fun userDao(): UserDao
    4. companion object {
    5. @Volatile
    6. private var INSTANCE: AppDatabase? = null
    7. fun getInstance(): AppDatabase {
    8. synchronized(this) {
    9. var instance = INSTANCE
    10. if (instance == null) {
    11. instance = Room.databaseBuilder(MyApplication.instance(), AppDatabase::class.java, "my-database-name")
    12. .allowMainThreadQueries()
    13. .build()
    14. INSTANCE = instance
    15. }
    16. return instance
    17. }
    18. }
    19. }
    20. }

    这里定义了一个AppDatabase单例,可以在全局中时候 AppDatabase实例

    5.定义:ViewModel

    1. class MyViewModel : ViewModel() {
    2. fun getUsersList(): LiveData>? {
    3. return AppDatabase.getInstance().userDao().getAll()
    4. }
    5. }

    6.Activity中添加 viewModel的:observe:

    1. viewModel.getUsersList()?.observe(this) {
    2. //获取到db 的数据后,开始显示到View上
    3. }

    7.创建Adapter ,这里的Adapter 结合了:AsyncListDiffer:https://developer.android.com/reference/androidx/recyclerview/widget/AsyncListDiffer

    1. public class UserAdapter extends RecyclerView.Adapter {
    2. private final AsyncListDiffer mDiffer = new AsyncListDiffer(this, DIFF_CALLBACK);
    3. @Override
    4. public int getItemCount() {
    5. int size = mDiffer.getCurrentList().size();
    6. return size;
    7. }
    8. public void submitList(List list) {
    9. mDiffer.submitList(list);
    10. }
    11. @NonNull
    12. @Override
    13. public UserViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
    14. return new UserViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_user_adapter, viewGroup, false));
    15. }
    16. @Override
    17. public void onBindViewHolder(UserViewHolder holder, int position) {
    18. User user = mDiffer.getCurrentList().get(position);
    19. holder.bindView(user, position);
    20. }
    21. public class UserViewHolder extends RecyclerView.ViewHolder {
    22. TextView mIdView;
    23. TextView mFirstNameView;
    24. TextView mLastNameView;
    25. public UserViewHolder(@NonNull View itemView) {
    26. super(itemView);
    27. mIdView = itemView.findViewById(R.id.tv_id);
    28. mFirstNameView = itemView.findViewById(R.id.tv_first_name);
    29. mLastNameView = itemView.findViewById(R.id.tv_last_name);
    30. }
    31. public void bindView(User user, int position) {
    32. mIdView.setText("Id:" + user.getUid());
    33. mFirstNameView.setText(user.getFirstName());
    34. mLastNameView.setText(user.getLastName());
    35. }
    36. }
    37. public static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() {
    38. @Override
    39. public boolean areItemsTheSame(
    40. @NonNull User oldUser, @NonNull User newUser) {
    41. // User properties may have changed if reloaded from the DB, but ID is fixed
    42. return oldUser.getUid() == newUser.getUid();
    43. }
    44. @Override
    45. public boolean areContentsTheSame(@NonNull User oldUser, @NonNull User newUser) {
    46. // NOTE: if you use equals, your object must properly override Object#equals()
    47. // Incorrectly returning false here will result in too many animations.
    48. return oldUser.equals(newUser);
    49. }
    50. };
    51. }

    8.接下来就要实现数据的增删改查,同步显示在View上了:

    插入数据:insert 

    1. mBinding.btnAddView.setOnClickListener {
    2. mCoroutineScope.launch {
    3. val localUserList = AppDatabase.getInstance().userDao().getAll2()
    4. val count = localUserList?.size ?: 0
    5. val targetCount = count + 1
    6. val user = User(targetCount, "FirstName:" + targetCount, "LastName:" + targetCount)
    7. AppDatabase.getInstance().userDao().insertOneUser(user)
    8. }
    9. }

    更新数据:update

    1. mBinding.btnEditView.setOnClickListener {
    2. mCoroutineScope.launch {
    3. val localUserList = AppDatabase.getInstance().userDao().getAll2()
    4. if (localUserList?.isNullOrEmpty() == true) {
    5. return@launch
    6. }
    7. localUserList?.forEach {
    8. it.firstName = it.firstName + "A"
    9. it.lastName = it.lastName + "B"
    10. }
    11. localUserList?.let {
    12. AppDatabase.getInstance().userDao().insertUserList(it)
    13. }
    14. }
    15. }

    删除数据:delete:

    1. mBinding.btnDeleteView.setOnClickListener {
    2. mCoroutineScope.launch {
    3. val localUserList = AppDatabase.getInstance().userDao().getAll2()
    4. localUserList?.let {
    5. val user = it?.get(it.size - 1)
    6. if (user != null) {
    7. AppDatabase.getInstance().userDao().delete(user)
    8. }
    9. }
    10. }
    11. }

    到目前为止就已经实现了:数据库的增删改查,同步显示到View 上:这样Room,ViewModel, AsyncListDiffer 结合在了一起

    Demo地址:GitHub - JasonZhangHG/DiffUtilDemo: Room DB + ViewModel + AsyncListDiffer

  • 相关阅读:
    并发编程——1.java内存图及相关内容
    云原生微服务 Spring Cloud Hystrix 降级、熔断实战应用
    入门Docker你不得不读的基础知识
    前端加密数据 后端java对应解密数据的方案
    Nginx的使用
    编写后台登录滑动成功获取验证码 人机验证
    DateTime 相关的操作汇总【C# 基础】
    python 多线程
    LeetCode链表练习(中)
    阿里巴巴编程规范实战(一):编程规约之OOP规约
  • 原文地址:https://blog.csdn.net/Jason_HD/article/details/127110754