当前位置:   article > 正文

Android Jetpack学习系列——Room

Android Jetpack学习系列——Room

关于Room:

Room是Android Jetpack组件之一,旨在为Android应用程序提供一种简单、强大且易于使用的本地数据库访问解决方案。

关键特性:

1.基于SQLite封装:Room是基于SQLite数据库引擎构建的,提供了面向对象的API来与SQLite交互,使得开发者无需直接编写SQL语句,降低了SQL错误风险,提高了代码可读性和可维护性。

2.编译时验证:Room利用注解处理器在编译时检查查询语句的有效性,提前发现潜在的SQL语法错误或类型不匹配等问题,增强了开发过程中的错误检查能力。

3.类型安全:Room通过提供数据访问对象(DAO)接口和数据模型类,确保了数据库操作与Java/Kotlin对象之间的类型安全转换,避免了运行时的类型转换异常。

4.LiveData / Flow 支持:Room可以轻松配合LiveData或Kotlin Flow实现数据变化的实时观察与响应,便于在UI层自动更新数据,适用于MVVM架构中的数据绑定。

5.事务管理:Room提供了便捷的事务管理机制,可以通过@Transaction注解在DAO方法上标记,确保一组数据库操作的原子性。

6.查询重用与优化:Room支持定义可重用的查询方法,同时也支持查询缓存以提高性能。

使用要点:

1.定义数据模型类:使用注解(如@Entity、@PrimaryKey、@ColumnInfo等)定义数据库表对应的Java或Kotlin类。

2.创建DAO接口:使用@Dao注解创建数据访问对象接口,定义查询、插入、更新、删除等数据库操作方法。

3.创建RoomDatabase子类:定义一个继承自RoomDatabase的抽象类,声明包含的实体类与DAO。

4.初始化数据库:在应用启动时创建并持有RoomDatabase实例,通常使用单例模式。

5.执行数据库操作:通过获取的DAO实例,调用其方法进行数据库操作。

好了,至此,前面的文案部分摘抄完毕,相信大家也从不少地方看到过很多理论知识,但是实践起来总不是那么的理想化,有各种各样的问题,对吧。

先来看本文实现的效果:


 

可以看到,demo实现的是非常基础的增删改查功能

下面开始具体的实现

本文使用的开发环境:

         Android Studio Iguana | 2023.2.1 Patch 1

Gradle版本:

        gradle-8.4-bin.zip 

1.引用依赖

  1. //room
  2. implementation 'androidx.room:room-runtime:2.6.1'
  3. annotationProcessor 'androidx.room:room-compiler:2.6.1'

 2.定义数据实体

  1. /**
  2. * 用户类,用于表示用户信息
  3. */
  4. @Entity
  5. public class User {
  6. // 主键,自动生成
  7. @PrimaryKey(autoGenerate = true)
  8. private long id;
  9. private String name; // 用户名
  10. private String age; // 年龄
  11. private String sex; // 性别
  12. /**
  13. * 构造函数,用于创建一个新的用户实例
  14. * @param name 用户名
  15. * @param age 年龄
  16. * @param sex 性别
  17. */
  18. public User(String name, String age, String sex) {
  19. this.name = name;
  20. this.age = age;
  21. this.sex = sex;
  22. }
  23. /**
  24. * 获取用户ID
  25. * @return 用户ID
  26. */
  27. public long getId() {
  28. return id;
  29. }
  30. /**
  31. * 设置用户ID
  32. * @param id 用户ID
  33. */
  34. public void setId(long id) {
  35. this.id = id;
  36. }
  37. /**
  38. * 获取用户名
  39. * @return 用户名
  40. */
  41. public String getName() {
  42. return name;
  43. }
  44. /**
  45. * 设置用户名
  46. * @param name 用户名
  47. */
  48. public void setName(String name) {
  49. this.name = name;
  50. }
  51. /**
  52. * 获取用户年龄
  53. * @return 用户年龄
  54. */
  55. public String getAge() {
  56. return age;
  57. }
  58. /**
  59. * 设置用户年龄
  60. * @param age 用户年龄
  61. */
  62. public void setAge(String age) {
  63. this.age = age;
  64. }
  65. /**
  66. * 获取用户性别
  67. * @return 用户性别
  68. */
  69. public String getSex() {
  70. return sex;
  71. }
  72. /**
  73. * 设置用户性别
  74. * @param sex 用户性别
  75. */
  76. public void setSex(String sex) {
  77. this.sex = sex;
  78. }
  79. }

3.定义Dao类

  1. /**
  2. * 用户数据访问接口,提供用户数据的增删改查操作。
  3. */
  4. @Dao
  5. public interface UserDao {
  6. /**
  7. * 插入用户信息到数据库。
  8. *
  9. * @param user 需要插入的用户对象。
  10. */
  11. @Insert
  12. void insertUser(User user);
  13. /**
  14. * 根据用户名查找用户。
  15. *
  16. * @param name 要查找的用户名,支持部分匹配。
  17. * @return 找到的第一个用户对象,如果没有找到返回null。
  18. */
  19. @Query("SELECT * FROM user WHERE name LIKE :name LIMIT 1")
  20. User findUserByName(String name);
  21. /**
  22. * 更新用户信息。
  23. *
  24. * @param user 需要更新的用户对象。
  25. */
  26. @Update
  27. void updateUser(User user);
  28. /**
  29. * 根据用户名删除用户。
  30. *
  31. * @param name 需要删除的用户的用户名。
  32. */
  33. @Query("DELETE FROM user WHERE name LIKE :name")
  34. void deleteUserByName(String name);
  35. /**
  36. * 查找所有用户信息。
  37. *
  38. * @return 用户列表,包含所有用户。
  39. */
  40. @Query("SELECT * FROM user")
  41. List<User> findAllUsers();
  42. /**
  43. * 删除所有用户信息。
  44. */
  45. @Query("DELETE FROM User")
  46. void deleteAllUsers();
  47. }

4.创建Database文件

  1. /**
  2. * 应用的数据库类,继承自RoomDatabase。用于定义数据库的结构和操作。
  3. * 使用单例模式确保全局仅有一个数据库实例。
  4. */
  5. @Database(entities = {User.class}, version = 1, exportSchema = false)
  6. public abstract class AppDatabase extends RoomDatabase {
  7. // 静态变量INSTANCE用于存储数据库的单例实例
  8. private static volatile AppDatabase INSTANCE;
  9. /**
  10. * 获取AppDatabase的单例实例。
  11. * 如果实例不存在,则通过Room的databaseBuilder创建一个新的实例。
  12. * 使用双重检查锁定确保线程安全。
  13. *
  14. * @param context 上下文对象,用于访问应用的资源和其他组件。
  15. * @return AppDatabase的单例实例。
  16. */
  17. public static AppDatabase getDatabase(Context context) {
  18. if (INSTANCE == null) {
  19. synchronized (AppDatabase.class) {
  20. if (INSTANCE == null) {
  21. // 通过Room的databaseBuilder构建数据库实例,配置数据库名称和实体类
  22. INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
  23. AppDatabase.class, DATABASE_NAME)
  24. .fallbackToDestructiveMigration() // 数据库升级时采用破坏性迁移策略
  25. .build();
  26. }
  27. }
  28. }
  29. return INSTANCE;
  30. }
  31. /**
  32. * 获取UserDao的抽象方法。UserDao是一个接口,用于操作用户数据。
  33. * 需要在具体实现类中提供该方法的具体实现。
  34. *
  35. * @return UserDao接口实例,用于进行用户数据的增删改查操作。
  36. */
  37. public abstract UserDao getUserDao();
  38. }

5.定义Constant类

  1. public class Constant {
  2. // 数据库名称常量
  3. public static final String DATABASE_NAME = "app_database";
  4. public static final String RESULT_MESSAGE_USER_NOT_EXIST = "用户不存在";
  5. public static final String RESULT_MESSAGE_USER_EXIST = "用户已存在";
  6. public static final String RESULT_MESSAGE_ERROR = "操作失败";
  7. }

至此,User表已经建立完成,接下来开始数据库操作方法

需要说明的是

本文实现的demo基于Android MVVM设计模式,所以并不会在Activity中直接操作数据库,一般来说,与用户相关的数据操作的部分需要放在ViewModel层,同时建议定义一个Repository来处理数据库操作,这样的话,最终的调用模式就是:

1.Repository层处理数据库的增删改查操作

2.ViewModel层处理与用户相关的数据操作逻辑

3.Activity用来更新UI

这样做一方面满足了MVVM的设计模式,同时也减轻了ViewModel层的负担

那么继续分享代码:

6.数据库操作类

  1. /**
  2. * 用户仓库类,负责用户数据的增删改查操作。
  3. */
  4. public class UserRepository {
  5. private final UserDao userDao;
  6. /**
  7. * 构造函数,初始化用户数据访问对象。
  8. *
  9. * @param database 应用数据库实例。
  10. */
  11. public UserRepository(AppDatabase database) {
  12. this.userDao = database.getUserDao();
  13. }
  14. /**
  15. * 插入用户。如果用户已存在,则操作失败。
  16. *
  17. * @param user 要插入的用户对象。
  18. * @return 返回操作结果,成功或失败。
  19. */
  20. @Transaction
  21. public UserRepositoryResult insertUser(User user) {
  22. // 检查用户是否已存在
  23. if (userDao.findUserByName(user.getName()) != null) {
  24. return new UserRepositoryResult(
  25. UserRepositoryResult.Type.FAILURE,
  26. RESULT_MESSAGE_USER_EXIST);
  27. }
  28. userDao.insertUser(user);
  29. return UserRepositoryResult.success();
  30. }
  31. /**
  32. * 更新用户信息。如果用户不存在,则操作失败。
  33. *
  34. * @param user 要更新的用户对象。
  35. * @return 返回操作结果,成功或失败。
  36. */
  37. @Transaction
  38. public UserRepositoryResult updateUser(User user) {
  39. // 确认用户存在
  40. User findUser = userDao.findUserByName(user.getName());
  41. if (findUser == null) {
  42. return new UserRepositoryResult(
  43. UserRepositoryResult.Type.FAILURE,
  44. RESULT_MESSAGE_USER_NOT_EXIST);
  45. }
  46. user.setId(findUser.getId());
  47. userDao.updateUser(user);
  48. return UserRepositoryResult.success();
  49. }
  50. /**
  51. * 根据用户名删除用户。如果用户不存在,则操作失败。
  52. *
  53. * @param name 要删除的用户的用户名。
  54. * @return 返回操作结果,成功或失败。
  55. */
  56. @Transaction
  57. public UserRepositoryResult deleteUserByName(String name) {
  58. // 确认用户存在
  59. if (userDao.findUserByName(name) == null) {
  60. return new UserRepositoryResult(
  61. UserRepositoryResult.Type.FAILURE,
  62. RESULT_MESSAGE_USER_NOT_EXIST);
  63. }
  64. userDao.deleteUserByName(name);
  65. return UserRepositoryResult.success();
  66. }
  67. /**
  68. * 删除所有用户。
  69. *
  70. * @return 返回操作结果,成功。
  71. */
  72. @Transaction
  73. public UserRepositoryResult deleteAllUsers() {
  74. userDao.deleteAllUsers();
  75. return UserRepositoryResult.success();
  76. }
  77. /**
  78. * 根据用户名查找用户。如果用户不存在,则操作失败。
  79. *
  80. * @param name 要查找的用户的用户名。
  81. * @return 返回操作结果,包含查找到的用户列表,如果未找到则列表为空。
  82. */
  83. @Transaction
  84. public UserRepositoryResult findUserByName(String name) {
  85. User user = userDao.findUserByName(name);
  86. // 处理用户不存在的情况
  87. if (user == null) {
  88. return new UserRepositoryResult(
  89. UserRepositoryResult.Type.FAILURE,
  90. RESULT_MESSAGE_USER_NOT_EXIST);
  91. }
  92. List<User> list = new ArrayList<>();
  93. list.add(user);
  94. return UserRepositoryResult.success(list);
  95. }
  96. /**
  97. * 查找所有用户。
  98. *
  99. * @return 返回操作结果,包含所有用户列表。
  100. */
  101. @Transaction
  102. public UserRepositoryResult findAllUsers() {
  103. List<User> list = userDao.findAllUsers();
  104. return UserRepositoryResult.success(list);
  105. }
  106. }

7.数据库操作结果类

  1. /**
  2. * 用户仓库操作结果类,用于封装用户操作的结果信息。
  3. */
  4. public class UserRepositoryResult {
  5. /**
  6. * 操作结果类型,包括成功和失败。
  7. */
  8. public enum Type {
  9. SUCCESS,
  10. FAILURE
  11. }
  12. private final Type type; // 操作结果类型
  13. private final String errorMessage; // 错误信息,当操作失败时使用
  14. // 成功操作时找到的用户列表
  15. private final List<User> foundUserList = new ArrayList<>();
  16. /**
  17. * 构造函数,用于创建一个操作结果实例。
  18. *
  19. * @param type 操作结果类型(成功或失败)。
  20. * @param errorMessage 错误信息,如果操作成功,则可以为null。
  21. */
  22. public UserRepositoryResult(Type type, String errorMessage) {
  23. this.type = type;
  24. this.errorMessage = errorMessage;
  25. }
  26. /**
  27. * 构造函数,用于创建一个包含用户列表的操作结果实例。
  28. *
  29. * @param type 操作结果类型(成功或失败)。
  30. * @param errorMessage 错误信息,如果操作成功,则可以为null。
  31. * @param foundUserList 找到的用户列表,如果操作没有找到用户,可以为null或空列表。
  32. */
  33. public UserRepositoryResult(Type type, String errorMessage, List<User> foundUserList) {
  34. this.type = type;
  35. this.errorMessage = errorMessage;
  36. if(null != foundUserList && !foundUserList.isEmpty()){
  37. this.foundUserList.addAll(foundUserList);
  38. }
  39. }
  40. /**
  41. * 获取操作结果类型。
  42. *
  43. * @return 返回操作结果类型(成功或失败)。
  44. */
  45. public Type getType() {
  46. return type;
  47. }
  48. /**
  49. * 获取错误信息。
  50. *
  51. * @return 如果操作成功,返回null;否则返回错误信息字符串。
  52. */
  53. public String getErrorMessage() {
  54. return errorMessage;
  55. }
  56. /**
  57. * 获取找到的用户列表。
  58. *
  59. * @return 返回操作成功时找到的用户列表,可能为空。
  60. */
  61. public List<User> getFoundUserList() {
  62. return foundUserList;
  63. }
  64. /**
  65. * 创建一个表示操作成功的UserRepositoryResult实例。
  66. *
  67. * @param foundUserList 找到的用户列表,可以为null。
  68. * @return 返回一个初始化为成功类型且包含指定用户列表的UserRepositoryResult实例。
  69. */
  70. public static UserRepositoryResult success(List<User> foundUserList) {
  71. return new UserRepositoryResult(Type.SUCCESS, null, foundUserList);
  72. }
  73. /**
  74. * 创建一个表示操作成功的UserRepositoryResult实例(不包含用户列表)。
  75. *
  76. * @return 返回一个初始化为成功类型且不包含用户列表的UserRepositoryResult实例。
  77. */
  78. public static UserRepositoryResult success() {
  79. return new UserRepositoryResult(Type.SUCCESS, null, null);
  80. }
  81. /**
  82. * 创建一个表示操作失败的UserRepositoryResult实例。
  83. *
  84. * @param errorMessage 错误信息字符串。
  85. * @return 返回一个初始化为失败类型且包含指定错误信息的UserRepositoryResult实例。
  86. */
  87. public static UserRepositoryResult failure(String errorMessage) {
  88. return new UserRepositoryResult(Type.FAILURE, errorMessage, null);
  89. }
  90. }

8.ViewModel代码

  1. /**
  2. * 主要的ViewModel类,用于处理与用户相关的数据操作。
  3. */
  4. public class MainViewModel extends ViewModel {
  5. // 用户数据仓库接口
  6. private final UserRepository userRepository;
  7. // 执行器服务,用于在后台线程中执行数据库操作
  8. private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
  9. /**
  10. * 构造函数,初始化用户数据仓库。
  11. *
  12. * @param userRepository 用户数据仓库实例。
  13. */
  14. public MainViewModel(UserRepository userRepository) {
  15. this.userRepository = userRepository;
  16. }
  17. // 用于存储插入用户操作结果的LiveData对象
  18. private final MutableLiveData<UserRepositoryResult> insertUserResult = new MutableLiveData<>();
  19. /**
  20. * 获取插入用户操作的结果。
  21. *
  22. * @return UserRepositoryResult 插入操作的结果。
  23. */
  24. public LiveData<UserRepositoryResult> getInsertUserResult() {
  25. return insertUserResult;
  26. }
  27. // 用于存储更新用户操作结果的LiveData对象
  28. private final MutableLiveData<UserRepositoryResult> updateUserResult = new MutableLiveData<>();
  29. /**
  30. * 获取更新用户操作的结果。
  31. *
  32. * @return UserRepositoryResult 更新操作的结果。
  33. */
  34. public LiveData<UserRepositoryResult> getUpdateUserResult() {
  35. return updateUserResult;
  36. }
  37. // 用于存储根据名称删除用户操作结果的LiveData对象
  38. private final MutableLiveData<UserRepositoryResult> deleteUserByNameResult = new MutableLiveData<>();
  39. /**
  40. * 获取根据名称删除用户操作的结果。
  41. *
  42. * @return UserRepositoryResult 删除操作的结果。
  43. */
  44. public LiveData<UserRepositoryResult> getDeleteUserByNameResult() {
  45. return deleteUserByNameResult;
  46. }
  47. // 用于存储删除所有用户操作结果的LiveData对象
  48. private final MutableLiveData<UserRepositoryResult> deleteAllUsersResult = new MutableLiveData<>();
  49. /**
  50. * 获取删除所有用户操作的结果。
  51. *
  52. * @return UserRepositoryResult 删除操作的结果。
  53. */
  54. public LiveData<UserRepositoryResult> getDeleteAllUsersResult() {
  55. return deleteAllUsersResult;
  56. }
  57. // 用于存储根据名称查找用户操作结果的LiveData对象
  58. private final MutableLiveData<UserRepositoryResult> findUserByNameResult = new MutableLiveData<>();
  59. /**
  60. * 获取根据名称查找用户操作的结果。
  61. *
  62. * @return UserRepositoryResult 查找操作的结果。
  63. */
  64. public LiveData<UserRepositoryResult> getFindUserByNameResult() {
  65. return findUserByNameResult;
  66. }
  67. // 用于存储查找所有用户操作结果的LiveData对象
  68. private final MutableLiveData<UserRepositoryResult> findAllUsersResult = new MutableLiveData<>();
  69. /**
  70. * 获取查找所有用户操作的结果。
  71. *
  72. * @return UserRepositoryResult 查找操作的结果。
  73. */
  74. public LiveData<UserRepositoryResult> getFindAllUsersResult() {
  75. return findAllUsersResult;
  76. }
  77. /**
  78. * 在后台线程中执行用户数据操作。
  79. */
  80. // 插入用户
  81. public void insertUser(final User user) {
  82. EXECUTOR_SERVICE.execute(() -> {
  83. insertUserResult.postValue(userRepository.insertUser(user));
  84. });
  85. }
  86. // 更新用户
  87. public void updateUser(final User user) {
  88. EXECUTOR_SERVICE.execute(() -> {
  89. updateUserResult.postValue(userRepository.updateUser(user));
  90. });
  91. }
  92. // 根据名称删除用户
  93. public void deleteUserByName(final String name) {
  94. EXECUTOR_SERVICE.execute(() -> {
  95. deleteUserByNameResult.postValue(userRepository.deleteUserByName(name));
  96. });
  97. }
  98. // 删除所有用户
  99. public void deleteAllUsers() {
  100. EXECUTOR_SERVICE.execute(() -> {
  101. deleteAllUsersResult.postValue(userRepository.deleteAllUsers());
  102. });
  103. }
  104. // 根据名称查找用户
  105. public void findUserByName(final String name) {
  106. EXECUTOR_SERVICE.execute(() -> {
  107. findUserByNameResult.postValue(userRepository.findUserByName(name));
  108. });
  109. }
  110. // 查找所有用户
  111. public void findAllUsers() {
  112. EXECUTOR_SERVICE.execute(() -> {
  113. findAllUsersResult.postValue(userRepository.findAllUsers());
  114. });
  115. }
  116. /**
  117. * ViewModel工厂类,用于创建MainViewModel实例。
  118. */
  119. public static class Factory extends ViewModelProvider.NewInstanceFactory {
  120. // 用户数据仓库实例
  121. private final UserRepository userRepository;
  122. /**
  123. * 构造函数,初始化用户数据仓库。
  124. *
  125. * @param userRepository 用户数据仓库实例。
  126. */
  127. public Factory(UserRepository userRepository) {
  128. this.userRepository = userRepository;
  129. }
  130. /**
  131. * 创建MainViewModel实例。
  132. *
  133. * @param modelClass ViewModel的类类型。
  134. * @return MainViewModel 实例。
  135. */
  136. @NonNull
  137. @Override
  138. public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
  139. return (T) new MainViewModel(userRepository);
  140. }
  141. }
  142. }

9.MainActivity调用

  1. /**
  2. * 主活动类,负责管理应用程序的主要界面。
  3. */
  4. public class MainActivity extends AppCompatActivity {
  5. private MainViewModel viewModel; // 视图模型,用于管理活动背后的业务逻辑
  6. private ActivityMainBinding binding; // 数据绑定实例,用于简化UI更新
  7. private UserRepository userRepository;
  8. /**
  9. * 在活动创建时调用。
  10. *shaoshao
  11. * @param savedInstanceState 如果活动之前被销毁,这参数包含之前的状态。如果活动没被销毁之前,这参数是null。
  12. */
  13. @Override
  14. protected void onCreate(Bundle savedInstanceState) {
  15. super.onCreate(savedInstanceState);
  16. // 启用边缘到边缘的UI
  17. EdgeToEdge.enable(this);
  18. // 设置数据绑定
  19. binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
  20. // 设置视图的内边距,以适应系统栏位的高度
  21. ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
  22. Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
  23. v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
  24. return insets;
  25. });
  26. userRepository = new UserRepository(AppDatabase.getDatabase(MVVMApplication.getInstance()));
  27. // 初始化视图模型
  28. viewModel = new ViewModelProvider(this, new MainViewModel.Factory(userRepository)).get(MainViewModel.class);
  29. binding.setViewModel(viewModel);
  30. initListeners();
  31. initObserver();
  32. }
  33. /**
  34. * 初始化视图监听器。
  35. */
  36. private void initListeners() {
  37. // 清空输入框操作监听
  38. binding.btnClearEdit.setOnClickListener(v -> {
  39. clearEditText();
  40. });
  41. // 插入用户操作监听
  42. binding.btnInsert.setOnClickListener(v -> {
  43. User userChecked = checkUserInfo();
  44. if (userChecked != null) {
  45. viewModel.insertUser(userChecked);
  46. }
  47. });
  48. // 根据姓名查找用户操作监听
  49. binding.btnFindByName.setOnClickListener(v -> {
  50. String nameChecked = checkName();
  51. if (!nameChecked.isEmpty()) {
  52. viewModel.findUserByName(nameChecked);
  53. }
  54. });
  55. // 更新用户操作监听
  56. binding.btnUpdate.setOnClickListener(v -> {
  57. User userChecked = checkUserInfo();
  58. if (userChecked != null) {
  59. viewModel.updateUser(userChecked);
  60. }
  61. });
  62. // 根据姓名删除用户操作监听
  63. binding.btnDeleteByName.setOnClickListener(v -> {
  64. String nameChecked = checkName();
  65. if (!nameChecked.isEmpty()) {
  66. viewModel.deleteUserByName(nameChecked);
  67. }
  68. });
  69. // 查找所有用户操作监听
  70. binding.btnFindAll.setOnClickListener(v -> {
  71. viewModel.findAllUsers();
  72. });
  73. // 删除所有用户操作监听
  74. binding.btnDeleteAll.setOnClickListener(v -> {
  75. viewModel.deleteAllUsers();
  76. });
  77. }
  78. private void initObserver() {
  79. // 观察插入结果
  80. viewModel.getInsertUserResult().observe(this, result -> {
  81. if (result.getType() == UserRepositoryResult.Type.SUCCESS) {
  82. showToast("添加成功");
  83. } else {
  84. showToast(result.getErrorMessage());
  85. }
  86. });
  87. // 观察查找结果
  88. viewModel.getFindUserByNameResult().observe(this, result -> {
  89. if (result.getType() == UserRepositoryResult.Type.SUCCESS) {
  90. if (!result.getFoundUserList().isEmpty()) {
  91. User user = result.getFoundUserList().get(0);
  92. binding.etName.setText(user.getName());
  93. binding.etAge.setText(user.getAge());
  94. binding.etSex.setText(user.getSex());
  95. } else {
  96. showToast("未找到该用户");
  97. }
  98. } else {
  99. showToast(result.getErrorMessage());
  100. }
  101. });
  102. // 观察更新结果
  103. viewModel.getUpdateUserResult().observe(this, result -> {
  104. if (result.getType() == UserRepositoryResult.Type.SUCCESS) {
  105. showToast("更新成功");
  106. } else {
  107. showToast(result.getErrorMessage());
  108. }
  109. });
  110. // 观察删除结果
  111. viewModel.getDeleteUserByNameResult().observe(this, result -> {
  112. if (result.getType() == UserRepositoryResult.Type.SUCCESS) {
  113. showToast("删除成功");
  114. } else {
  115. showToast(result.getErrorMessage());
  116. }
  117. });
  118. // 观察查找所有用户的结果
  119. viewModel.getFindAllUsersResult().observe(this, result -> {
  120. if (result.getType() == UserRepositoryResult.Type.SUCCESS) {
  121. List<User> userList = result.getFoundUserList();
  122. if (!userList.isEmpty()) {
  123. StringBuilder sb = new StringBuilder();
  124. for (User user : userList) {
  125. sb.append(user.getName()).append(" ").append(user.getAge()).append(" ").append(user.getSex()).append("\n");
  126. }
  127. showToast(sb.toString());
  128. } else {
  129. showToast("没有用户");
  130. }
  131. } else {
  132. showToast(result.getErrorMessage());
  133. }
  134. });
  135. // 观察删除所有用户的结果
  136. viewModel.getDeleteAllUsersResult().observe(this, result -> {
  137. if (result.getType() == UserRepositoryResult.Type.SUCCESS) {
  138. showToast("删除成功");
  139. } else {
  140. showToast(result.getErrorMessage());
  141. }
  142. });
  143. }
  144. // 封装对用户信息输入的验证
  145. private User checkUserInfo() {
  146. String name = binding.etName.getText().toString();
  147. if (name.isEmpty()) {
  148. showToast("请输入姓名");
  149. return null;
  150. }
  151. String age = binding.etAge.getText().toString();
  152. if (age.isEmpty()) {
  153. showToast("请输入年龄");
  154. return null;
  155. }
  156. String sex = binding.etSex.getText().toString();
  157. if (sex.isEmpty()) {
  158. showToast("请输入性别");
  159. return null;
  160. }
  161. return new User(name, age, sex);
  162. }
  163. // 封装对姓名输入的检查
  164. private String checkName() {
  165. String name = binding.etName.getText().toString();
  166. if (name.isEmpty()) {
  167. showToast("请输入姓名");
  168. return "";
  169. }
  170. return name;
  171. }
  172. // 清除编辑文本框中的内容
  173. private void clearEditText() {
  174. binding.etName.setText("");
  175. binding.etAge.setText("");
  176. binding.etSex.setText("");
  177. }
  178. // 简化Toast消息的显示
  179. private void showToast(String message) {
  180. Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
  181. }
  182. }

10.布局文件 

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <!--使用databinding功能,根布局需要使用<layout>标签 -->
  3. <layout xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:app="http://schemas.android.com/apk/res-auto"
  5. xmlns:tools="http://schemas.android.com/tools">
  6. <!-- 这是Data Binding的<data>标签,用于定义布局中使用的数据对象和表达式-->
  7. <data>
  8. <variable
  9. name="viewModel"
  10. type="com.example.mvvmdemo.ui.main.MainViewModel" />
  11. </data>
  12. <androidx.constraintlayout.widget.ConstraintLayout
  13. android:id="@+id/main"
  14. android:layout_width="match_parent"
  15. android:layout_height="match_parent"
  16. tools:context=".ui.main.MainActivity">
  17. <EditText
  18. android:id="@+id/et_name"
  19. android:layout_width="0dp"
  20. android:layout_height="wrap_content"
  21. android:layout_marginStart="10dp"
  22. android:layout_marginEnd="10dp"
  23. android:ems="10"
  24. android:hint="姓名"
  25. android:inputType="text"
  26. app:layout_constraintBottom_toBottomOf="parent"
  27. app:layout_constraintEnd_toEndOf="parent"
  28. app:layout_constraintStart_toStartOf="parent"
  29. app:layout_constraintTop_toTopOf="parent"
  30. app:layout_constraintVertical_bias="0.05" />
  31. <EditText
  32. android:id="@+id/et_age"
  33. android:layout_width="0dp"
  34. android:layout_height="wrap_content"
  35. android:layout_marginStart="10dp"
  36. android:layout_marginTop="10dp"
  37. android:layout_marginEnd="10dp"
  38. android:ems="10"
  39. android:hint="年龄"
  40. android:inputType="text"
  41. app:layout_constraintEnd_toEndOf="parent"
  42. app:layout_constraintStart_toStartOf="parent"
  43. app:layout_constraintTop_toBottomOf="@+id/et_name" />
  44. <EditText
  45. android:id="@+id/et_sex"
  46. android:layout_width="0dp"
  47. android:layout_height="wrap_content"
  48. android:layout_marginStart="10dp"
  49. android:layout_marginTop="10dp"
  50. android:layout_marginEnd="10dp"
  51. android:ems="10"
  52. android:hint="性别"
  53. android:inputType="text"
  54. app:layout_constraintEnd_toEndOf="parent"
  55. app:layout_constraintStart_toStartOf="parent"
  56. app:layout_constraintTop_toBottomOf="@+id/et_age" />
  57. <Button
  58. android:id="@+id/btn_insert"
  59. android:layout_width="0dp"
  60. android:layout_height="wrap_content"
  61. android:layout_marginStart="10dp"
  62. android:layout_marginTop="10dp"
  63. android:layout_marginEnd="10dp"
  64. android:text="增加"
  65. app:layout_constraintEnd_toEndOf="parent"
  66. app:layout_constraintHorizontal_bias="1.0"
  67. app:layout_constraintStart_toStartOf="parent"
  68. app:layout_constraintTop_toBottomOf="@+id/btn_clear_edit" />
  69. <Button
  70. android:id="@+id/btn_find_by_name"
  71. android:layout_width="0dp"
  72. android:layout_height="wrap_content"
  73. android:layout_marginStart="10dp"
  74. android:layout_marginTop="10dp"
  75. android:layout_marginEnd="10dp"
  76. android:text="根据姓名查询"
  77. app:layout_constraintEnd_toEndOf="parent"
  78. app:layout_constraintStart_toStartOf="parent"
  79. app:layout_constraintTop_toBottomOf="@+id/btn_insert" />
  80. <Button
  81. android:id="@+id/btn_update"
  82. android:layout_width="0dp"
  83. android:layout_height="wrap_content"
  84. android:layout_marginStart="10dp"
  85. android:layout_marginTop="10dp"
  86. android:layout_marginEnd="10dp"
  87. android:text="更新"
  88. app:layout_constraintEnd_toEndOf="parent"
  89. app:layout_constraintHorizontal_bias="0.0"
  90. app:layout_constraintStart_toStartOf="parent"
  91. app:layout_constraintTop_toBottomOf="@+id/btn_find_by_name" />
  92. <Button
  93. android:id="@+id/btn_find_all"
  94. android:layout_width="0dp"
  95. android:layout_height="wrap_content"
  96. android:layout_marginStart="10dp"
  97. android:layout_marginTop="10dp"
  98. android:layout_marginEnd="10dp"
  99. android:text="查询所有"
  100. app:layout_constraintEnd_toEndOf="parent"
  101. app:layout_constraintHorizontal_bias="0.0"
  102. app:layout_constraintStart_toStartOf="parent"
  103. app:layout_constraintTop_toBottomOf="@+id/btn_delete_by_name" />
  104. <Button
  105. android:id="@+id/btn_delete_by_name"
  106. android:layout_width="0dp"
  107. android:layout_height="wrap_content"
  108. android:layout_marginStart="10dp"
  109. android:layout_marginTop="10dp"
  110. android:layout_marginEnd="10dp"
  111. android:text="根据姓名删除"
  112. app:layout_constraintEnd_toEndOf="parent"
  113. app:layout_constraintStart_toStartOf="parent"
  114. app:layout_constraintTop_toBottomOf="@+id/btn_update" />
  115. <Button
  116. android:id="@+id/btn_delete_all"
  117. android:layout_width="0dp"
  118. android:layout_height="wrap_content"
  119. android:layout_marginStart="10dp"
  120. android:layout_marginTop="10dp"
  121. android:layout_marginEnd="10dp"
  122. android:layout_marginBottom="80dp"
  123. android:text="清空数据表"
  124. app:layout_constraintBottom_toBottomOf="parent"
  125. app:layout_constraintEnd_toEndOf="parent"
  126. app:layout_constraintHorizontal_bias="1.0"
  127. app:layout_constraintStart_toStartOf="parent"
  128. app:layout_constraintTop_toBottomOf="@+id/btn_find_all"
  129. app:layout_constraintVertical_bias="0.0" />
  130. <Button
  131. android:id="@+id/btn_clear_edit"
  132. android:layout_width="wrap_content"
  133. android:layout_height="wrap_content"
  134. android:layout_marginTop="10dp"
  135. android:text="清空输入"
  136. app:layout_constraintEnd_toEndOf="parent"
  137. app:layout_constraintStart_toStartOf="parent"
  138. app:layout_constraintTop_toBottomOf="@+id/et_sex" />
  139. </androidx.constraintlayout.widget.ConstraintLayout>
  140. </layout>

写在最后 

        其实关于MVVM的代码并不好写,因为MVVM是一种编程思想,并没有确定的写法和流派,所以建议每一个学习MVVM的同学,不要只是盲目的死扣形式,而是要追求代码的内在。不管是何种形式,只要是使得代码条理更清晰,功能稳定,就是好代码。代码这种东西,没有尽头,今天我们学习MVVM设计模式,可能不知道什么时候,又兴起来一种新的形式,就像潮起潮落一样。

然后关于我上面展示的代码,我没有做过多的解释,主要是快下班了,我今天太想要把这篇积压已久的文章整理好发出去,哈哈。不过也附带了足够多的代码注释,如果你真的很希望掌握Room的用法,也建议你能够对照着代码多看,然后在自己的开发环境里多运行几次,然后把demo进行一些功能扩展和修改,相信你一定可以掌握的很好。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/474429
推荐阅读
相关标签
  

闽ICP备14008679号