Android技术知识Android开发经验谈Android开发

06 Jetpack-Room

2021-11-30  本文已影响0人  凤邪摩羯

一、基础使用

1.1 Room三个主要操作类

image

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实现有则更新无则插入

@Entity(tableName = "chatrow", indices = {@Index(value = {"name"}, unique = true)} )  //数据库实体类
public class User {...}

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

四、数据库版本迁移

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();

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");
    }
};

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");
    }
};

上一篇下一篇

猜你喜欢

热点阅读