Android Room 笔记
导入
在app.build.gradle
中的dependecies{}
代码块内添加如下引用
def room_version = "2.2.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor
// optional - RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
建库
创建继承自androidx.room.RoomDatabase
的抽象类,并为该类添加注解,如下所示
@Database(entities = {User.class, Login.class}, version = 1)
public abstract class DatabaseName extends RoomDatabase {
...
}
@Database(entities = arrayOf(User::class, Login::class), version = 1)
abstract class DatabaseName: RoomDatabase() {
...
}
该例子建立了一个拥有User、Login两张表的版本为1的数据库
之后对数据库进行初始化(建议在Application中进行)
初始化示例如下
void initDB(Context ctx, String dbName){
DatabaseName db = Room.databaseBuilder(ctx.getApplicationContext(), DatabaseName.class, dbName).build();
}
fun initDB(ctx: Context, dbName: String){
val db = Room.databaseBuilder(ctx.applicationContext, DatabaseName::class.java, dbName).build()
}
获取到DatabaseName实例后,建议确保其为单例模式使用,因为每次获取的开销都不小
使用@Database
的类应满足以下条件
- 继承自
RoomDatabase
的抽象类 - 在注释中添加与数据库关联的实体列表
- 包含无参且返回通过
@Dao
注释的类的抽象方法(在建表部分详细解释)
建表
@Entity
通过由@Entity
注解修饰的Java Bean类来构建,请确保各个属性对Room来说都是可见的
基本用法
@Entity
public class User {
@PrimaryKey
public long uid;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
}
@Entity
data class User(
@PrimaryKey val uid: Int,
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?
)
如上创建了一个User表,包含一个主键uid和两个字段。
自增主键
通过@PrimaryKey
修饰的字段会被当成主键。若需要该主键自动生成,可以使用如下写法
@PrimaryKey(autoGenerate = true)
public long uid;
复合主键
每个实体必须至少有一个字段为主键。通过@Entity(primaryKeys = [])
来进行配置,此时请不要使用@PrimaryKey
修饰其它字段,并确保主键均为NonNull
类型
@Entity(primaryKeys = {"firstName", "lastName"})
public class User {
@NonNull
public String firstName;
@NonNull
public String lastName;
}
@Entity(primaryKeys = arrayOf("firstName", "lastName"))
data class User(
val firstName: String,
val lastName: String
)
定义字段名
默认下,数据库将用类名作为表名。若希望规定不同名称,可以使用@Entity
的tableName
属性(数据库名称不区分大小写)
@Entity(tableName = "users")
public class User {
...
}
@Entity(tableName = "users")
data class User (
...
)
同样的,可以用@ColumnInfo
的name
属性定义字段名
忽略字段
Room会为实体的每一个字段创建一个类。如果有些字段并非用来建表,可以使用@Ignore
为其进行注释
若其存在继承关系,则建议使用@Entity
的ignoredColumns
进行注释
官方的示例如下
@Entity(ignoredColumns = "picture")
public class RemoteUser extends User {
@PrimaryKey
public int id;
public boolean hasVpn;
}
open class User {
var picture: Bitmap? = null
}
@Entity(ignoredColumns = arrayOf("picture"))
data class RemoteUser(
@PrimaryKey val id: Int,
val hasVpn: Boolean
) : User()
字段唯一
部分数据库中的字段或字段组内容必须唯一,可以用@Index
的unique
属性进行设置。当尝试插入重复字段时会抛出RuntimeException
@Entity(indices = {@Index(value = {"first_name", "last_name"},
unique = true)})
public class User {
@PrimaryKey
public int id;
@ColumnInfo(name = "first_name")
public String firstName;
@ColumnInfo(name = "last_name")
public String lastName;
@Ignore
Bitmap picture;
}
@Entity(indices = arrayOf(Index(value = ["first_name", "last_name"],
unique = true)))
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "first_name") val firstName: String?,
@ColumnInfo(name = "last_name") val lastName: String?,
@Ignore var picture: Bitmap?
)
@Dao
使用@Dao修饰的接口类来确定业务接口。该接口最后会通过生成Room.databaseBuilder
时实现其前文提到的无参抽象方法来获取。
官方示例非常清晰
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List<User> getAll();
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
@Insert
void insertAll(User... users);
@Delete
void delete(User user);
}
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Query("SELECT * FROM user WHERE uid IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<User>
@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
fun findByName(first: String, last: String): User
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
}
记得在之前编写的DatabaseName.class
中添加获取该类实例的抽象方法
@Database(entities = {User.class, Login.class}, version = 1)
public abstract class DatabaseName extends RoomDatabase {
public abstract UserDao getUserDao();
}
@Database(entities = {User.class, Login.class}, version = 1)
public abstract class DatabaseName extends RoomDatabase {
abstract fun userDao(): UserDao
}
在实际操作中,即可使用得到的数据库类实例来进行操作
void sampleFun(){
DatabaseName db = Room.databaseBuilder(ctx.getApplicationContext(), DatabaseName.class, dbName).build();
//查询所有用户
List<User> userList = db.getUserDao().getAll();
}
fun sampleFun(){
val db = Room.databaseBuilder(ctx.applicationContext, DatabaseName::class.java, dbName).build()
val userList = db.userDao.all
}