• 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进行一些功能扩展和修改,相信你一定可以掌握的很好。

  • 相关阅读:
    308. 二维区域和检索 - 可变 线段树/哈希
    安吉尔直饮水设备保质交付,深圳湾公园直饮水保障完成
    高性能MySQL实战开篇寄语:建立完整的MySQL知识体系
    [uni-app] scroll-view中吸顶的简单做法 - overflow-y: auto;
    【持续更新】C/C++ 踩坑记录(一)
    Greenplum数据库外部协议——GPHDFS实现协议
    微信支付(微信浏览器支付WeixinJSBridge.invoke)
    小白C语言编程实战(22):结构体的应用
    JVS规则引擎,打造智能自动化决策的利器
    VUE:组件
  • 原文地址:https://blog.csdn.net/weixin_53324308/article/details/137829905