06 Jetpack-Room

作者: 凤邪摩羯 | 来源:发表于2021-11-30 09:29 被阅读0次

    一、基础使用

    1.1 Room三个主要操作类

    image
    • Entity代表一个表中的字段
    • Dao数据库操作接口增删改查
    • 管理创建数据库

    1.2 引入依赖

    https://developer.android.com/jetpack/androidx/releases/room
    选择性引入

    dependencies {
      def room_version = "2.2.5"
    
      implementation "androidx.room:room-runtime:$room_version"
      annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
    
      // optional - Kotlin Extensions and Coroutines support for Room
      // implementation "androidx.room:room-ktx:$room_version"
    
      // optional - RxJava support for Room
      // implementation "androidx.room:room-rxjava2:$room_version"
    
      // optional - Guava support for Room, including Optional and ListenableFuture
      // implementation "androidx.room:room-guava:$room_version"
    
      // Test helpers
      testImplementation "androidx.room:room-testing:$room_version"
    }
    
    

    1.3 创建数据库实体 Entity

    @Entity(tableName = "User")  //数据库实体类
    public class User {
        //主键 自增
        @PrimaryKey(autoGenerate = true)
        private int id;
        @ColumnInfo(name = "user_name") //实际数据库中的字段user_name
        private String name;
        @ColumnInfo(name = "user_gender")
        private String gender;
        private int age;
    
        public User(int id, String name, String gender, int age) {
            this.id = id;
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
    
        public User(String name, String gender, int age) {
            this.name = name;
            this.gender = gender;
            this.age = age;
        }
      // 省略 get set ......
    }
    
    

    1.4 创建数据库操作接口 Dao

    @Dao //Database access object  数据库访问接口 所有增删改查等操作都在此声明
    public interface UserDao {
    
        // long 表示插入数据后返回的id
        @Insert
        void insertUser(User... users);
    
        // int 影响的行数
        @Update
        int updateUser(User... users);
    
        @Delete
        void deleteUser(User... users);
    
        @Query("DELETE FROM USER")
        void deleteUser();
    
        @Query("SELECT * FROM USER ORDER BY ID DESC")
        List<User> getAllUser();
    }
    
    

    1.4.1 唯一约束+REPLACE实现有则更新无则插入

    • 实体类中通过indices 将name字段设置成唯一约束
    @Entity(tableName = "chatrow", indices = {@Index(value = {"name"}, unique = true)} )  //数据库实体类
    public class User {...}
    
    
    • Dao中插入语句设置onConflict插入模式
    public interface UserDao {
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        void insertUser(User... users);
    }
    
    

    1.5 创建数据库管理 Database

    // entities ={多个集合逗号隔开}
    @Database(entities = {User.class}, version = 1, exportSchema = false)
    public abstract class UserDatabase extends RoomDatabase {
        public abstract UserDao getUserDao();
        // 若entities有多个实例,则应该写多个Dao
    }
    
    

    1.6 使用

    操作数据库必须在子线程中,为了简单此处直接使用allowMainThreadQueries()强制在主线程运行,正常开发不允许

    UserDatabase userDatabase = Room.databaseBuilder(this, UserDatabase.class, "user")
            .allowMainThreadQueries()//强制在主线程运行 不建议
            .build();
    UserDao userDao = userDatabase.getUserDao();
    //增加
    userDao.insertUser(new User("nikola", "男", 22));
    //修改ID为3的
    int row = userDao.updateUser(new User(3, "kolia", "女", 22));
    //查询所有
    List<User> allUser = userDao.getAllUser();
    
    

    二、使用单例注意事项

    Google官方称创建数据库实例较耗时,所以使用单例模式,但要注意: 无参构造方法不能使用private修饰 否则Room自动生成实现类时会报错

    // entities ={多个集合逗号隔开}
    @Database(entities = {User.class}, version = 1, exportSchema = false)
    public abstract class UserDatabase extends RoomDatabase {
    
        public UserDatabase() {
        }
    
        private static UserDatabase userDatabase;
    
        synchronized public static UserDatabase getUserDatabase(Context context) {
            if (null == userDatabase) {
                userDatabase = Room.databaseBuilder(context.getApplicationContext(), UserDatabase.class, "user")
                        .allowMainThreadQueries() //强制在主线程运行 不建议
                        .build();
            }
            return userDatabase;
        }
    
        public abstract UserDao getUserDao();
        // 若entities有多个实例,则应该写多个Dao
    }
    
    

    三、 LiveData 监听数据库变化

    3.1 返回值使用LiveData包装

    数据变化只在查询时提现,所以修改UserDao中查询所有的返回值类型, 且LiveData内部已经实现再子线程中执行,可以直接调用

    @Query("SELECT * FROM USER ORDER BY ID DESC")
        // List<User> getAllUser();
        LiveData<List<User>> getAllUserLive();
    
    

    3.2 设置监听

    LiveData<List<User>> listLiveData  = userDao.getAllUserLive();
    listLiveData.observe(this, new Observer<List<User>>() {
        @Override
        public void onChanged(List<User> users) {
         ......
        }
    });
    
    

    当对数据库进行增删改时会回调onChanged

    四、数据库版本迁移

    • 变更Entity中的字段 要增加 Database中的version,
    • 迁移数据库有保留原有数据与 破坏式清空原有数据

    4.1 破坏式

    allowMainThreadQueries 不保留数据直接删除原有数据库

    UserDatabase userDatabase = Room.databaseBuilder(this, UserDatabase.class, "user")
        .allowMainThreadQueries()//强制在主线程运行 不建议
        .fallbackToDestructiveMigration() //破坏式: 当数据库版本变化时不做数据迁移
        .build();
    
    

    4.2 保留原有数据迁移

    当Entity字段改变时调用.addMigrations(Migration... migrations),指定从某个版本迁移到某个版本需要做的某项操作,具体操作定义在Migration中

    UserDatabase userDatabase = Room.databaseBuilder(this, UserDatabase.class, "user")
        .allowMainThreadQueries()//强制在主线程运行 不建议
        .addMigrations(migration) //保留原有数据
        .build();
    
    
    • 表中增加type字段时的addMigrations 实参 migration如下,需要自行写增加字段语句
    static final Migration migration = new Migration(2,3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE user ADD COLUMN type INTEGER NOT NULL DEFAULT 1");
        }
    };
    
    
    • 删除某个字段,sqlLet没有删除字段语句,只能创建新的数据库定义需要的字段,将原有数据库数据复制过去,删除旧数据库后再将新数据库重命名
      new Migration(3,4) 表示从版本3升级到版本4
    static final Migration migration = new Migration(3,4) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("CREATE TABLE user_temp (id INTEGER PRIMARY KEY NOT NULL , user_name TEXT," +
                    "user_gender TEXT)");
            database.execSQL("INSERT INTO user_temp (id, user_name, user_gender) " +
                    "SELECT id, user_name, user_gender FROM user");
            database.execSQL("DROP TABLE user");
            database.execSQL("ALTER TABLE user_temp RENAME to user");
        }
    };
    
    

    相关文章

      网友评论

        本文标题:06 Jetpack-Room

        本文链接:https://www.haomeiwen.com/subject/guibyltx.html