@Entity(tableName = "ble_device")
public class BleDeviceEntity {
@PrimaryKey(autoGenerate = true)
private int id;
@NonNull
@ColumnInfo(name = "device_address")
private String address;
private String name;
private int rssi;
@ColumnInfo(name = "last_seen")
private long lastSeenTimestamp;
// 构造函数、Getter、Setter 省略
}
最佳实践:Entity 字段尽量使用基本类型 + String,避免复杂嵌套对象。若必须存储,需配合 TypeConverter。
#### 2.2.2 DAO — 数据操作接口
DAO 是接口或抽象类,使用 `@Dao` 注解。方法上标注 `@Insert`、`@Update`、`@Delete`、`@Query` 等。
@Dao
public interface BleDeviceDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(BleDeviceEntity device);
@Update
void update(BleDeviceEntity device);
@Delete
void delete(BleDeviceEntity device);
@Query("SELECT * FROM ble_device ORDER BY last_seen DESC")
LiveData<List<BleDeviceEntity>> getAllDevices();
@Query("SELECT * FROM ble_device WHERE device_address = :address")
BleDeviceEntity getDeviceByAddress(String address);
}
#### 2.2.3 TypeConverter — 自定义类型转换
Room 默认支持基本类型、String、ByteArray。若需存储 Date、List 等,需编写转换器。
public class Converters {
@TypeConverter
public static Date fromTimestamp(Long value) {
return value == null ? null : new Date(value);
}
@TypeConverter
public static Long dateToTimestamp(Date date) {
return date == null ? null : date.getTime();
}
@TypeConverter
public static List<String> fromString(String value) {
if (value == null) return null;
return Arrays.asList(value.split(","));
}
@TypeConverter
public static String fromList(List<String> list) {
if (list == null) return null;
return String.join(",", list);
}
}
#### 2.2.4 Database — 数据库定义与初始化
数据库类继承 `RoomDatabase`,使用 `@Database` 注解声明 entities、version,并绑定 TypeConverters。
@Database(
entities = {BleDeviceEntity.class},
version = 1,
exportSchema = false
)
@TypeConverters(Converters.class)
public abstract class BleDeviceDatabase extends RoomDatabase {
public abstract BleDeviceDao bleDeviceDao();
private static volatile BleDeviceDatabase INSTANCE;
public static BleDeviceDatabase getInstance(Context context) {
if (INSTANCE == null) {
synchronized (BleDeviceDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context.getApplicationContext(),
BleDeviceDatabase.class,
"ble_device_db"
)
.fallbackToDestructiveMigration()
.build();
}
}
}
return INSTANCE;
}
}
### 2.3 配置与初始化要点
| 配置项 | 说明 | 推荐值 |
|--------|------|--------|
| `entities` | 声明所有 Entity 类 | 数组形式,如 `{BleDeviceEntity.class}` |
| `version` | 数据库版本号,升级时递增 | 起始 1 |
| `exportSchema` | 是否导出 Schema 到文件 | 调试阶段设为 true,发布 false |
| `@TypeConverters` | 关联自定义转换器类 | 作用于 Database 类 |
| `.fallbackToDestructiveMigration()` | 版本不匹配时直接删除重建 | 开发阶段使用,生产环境需谨慎 |
| `.addMigrations(Migration... migration)` | 定义迁移策略 | 生产环境推荐 |
### 2.4 调试与验证
**检查生成的 DAO 实现** 可查看 `build/generated/source/apt/debug/` 目录下的文件。
**常见错误排查:**
典型错误 1:Entity 缺少无参构造函数或主键 —— 编译报错 “Entities must have a primary key”。
典型错误 2:TypeConverter 未注册,存储 Date 时出现 “Cannot figure out how to save this field into database”。
典型错误 3:Database 未使用单例模式,造成多次打开数据库连接 — 使用 volatile + synchronized 解决。
### 2.5 性能与稳定性优化
- **DAO 方法使用 `LiveData` 或 `Flow`**,实现自动通知 UI 更新,避免手动刷新。
- **事务操作** 在 DAO 方法上添加 `@Transaction`,保证批量插入/更新的原子性。
- **索引优化**:在查询频繁的字段上添加 `@Index`,例如 `@Entity(indices = {@Index("device_address")})`。
- **预编译 WAL 模式**:Room 默认启用 WAL(Write-Ahead Logging),提高并发读写性能。无需手动配置。
- **迁移策略**:生产环境必须使用 `addMigrations()` 逐步迁移,避免 `fallbackToDestructiveMigration()` 造成数据丢失。
// 迁移示例:从版本 1 升级到 2
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE ble_device ADD COLUMN battery_level INTEGER DEFAULT 0");
}
};
### 2.6 组件集成验证清单
- [ ] Entity 已添加 `@Entity` 并指定主键
- [ ] DAO 接口已标注 `@Dao`,SQL 语法正确
- [ ] TypeConverter 类已编写并用 `@TypeConverters` 关联到 Database
- [ ] Database 类继承 `RoomDatabase`,**单例模式**实现 getInstance
- [ ] 数据库名称唯一(避免与其他模块冲突)
- [ ] Version 号随表结构变化递增
- [ ] 生产环境使用 `addMigrations()` 而非 `fallbackToDestructiveMigration()`
- [ ] 性能敏感查询添加索引和 `@Transaction`