Android-Jetpack笔记-Room

Room是一种ORM(对象关系映射)框架,可以用OOP(面向对象)的思路开发数据库,有点像早期的greenDAO,不过Room作为Jetpack的一员,能够返回更多类型的数据,比如能直接返回DataSource.Factory来友好的支持Paging的使用,本文主要总结基础的使用和原理。

Jetpack笔记代码

本文源码基于SDK 29

使用

引入依赖:

1
2
3
4
def room_version = "2.2.3"
implementation "androidx.room:room-runtime:$room_version"
//注解处理器,用于编译期根据注解来生成类
annotationProcessor "androidx.room:room-compiler:$room_version"

@Entity表示一个实体,即数据库中表的定义,

1
2
3
4
5
6
7
8
9
10
//声明一个实体User,表名为t_user
@Entity(tableName = "t_user")
class User {
@PrimaryKey(autoGenerate = true) //int型的自增主键
@ColumnInfo(name = "id") //表中字段的名字,不填则使用成员变量名
private int mId;

@Ignore //Ignore注解表示不进行数据库映射,只存在于内存中
private boolean mSelected;
}

使用@Dao声明数据访问对象,即表的操作,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE) //新增数据,发生冲突则替换
void insertUsers(User... users);

@Update(onConflict = OnConflictStrategy.REPLACE) //更新数据,发生冲突则替换
int updateUsers(User... users);

@Delete
void deleteUsers(User... users); //删除数据

@Query("SELECT * FROM t_user") //查询数据
List<User> queryUsers();
}

定义完表,还需要用@Database定义数据库,

1
2
3
4
5
6
//entities表示这个数据库都有哪些表,version表示数据库版本,用于数据库升级
@Database(entities = {User.class}, version = 1)
abstract class AppDatabase extends RoomDatabase {
//提供dao对象给业务层使用
public abstract UserDao userDao();
}

来到activity,进行使用

1
2
3
4
5
6
7
8
9
10
11
12
RoomActivity extends AppCompatActivity {
void onCreate(Bundle savedInstanceState) {
//创建数据库对象
mAppDatabase = Room.databaseBuilder(this, AppDatabase.class, AppDatabase.DB_NAME)
.allowMainThreadQueries() //允许主线程操作数据库,不推荐
.build();
//获取dao对象
mUserDao = mAppDatabase.userDao();
//操作数据库
mUserDao.insertUsers(user);
}
}

原理

首先看看数据库的创建,进入AppDatabase类,点击查看他的实现类AppDatabase_Impl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//AppDatabase_Impl.java
SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) {
void createAllTables(SupportSQLiteDatabase _db) {
//创建表
_db.execSQL("CREATE TABLE IF NOT EXISTS `t_user` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)");
}
};
}

@Override
public UserDao userDao() {
if (_userDao != null) {
return _userDao;
} else {
synchronized(this) {
if(_userDao == null) {
//创建dao对象
_userDao = new UserDao_Impl(this);
}
return _userDao;
}
}
}

来到UserDao_Impl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//UserDao_Impl.java
UserDao_Impl(RoomDatabase __db) {
this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {
@Override
public String createQuery() {
//创建sql语句
return "INSERT OR REPLACE INTO `t_user` (`id`,`name`) VALUES (nullif(?, 0),?)";
}

@Override
public void bind(SupportSQLiteStatement stmt, User value) {
//将参数绑定到sql语句的指定位置
stmt.bindLong(1, value.getId());
if (value.getName() == null) {
stmt.bindNull(2);
} else {
stmt.bindString(2, value.getName());
}
}
};
}

@Override
public void insertUsers(final User... users) {
__insertionAdapterOfUser.insert(users);
}

insert会来到EntityInsertionAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//EntityInsertionAdapter.java
void insert(T[] entities) {
final SupportSQLiteStatement stmt = acquire();
try {
for (T entity : entities) {
//根据前边实现的bind方法,绑定参数
bind(stmt, entity);
//执行stmt完成数据库操作
stmt.executeInsert();
}
} finally {
release(stmt);
}
}

//省略调用链:acquire - getStmt - createNewStatement
SupportSQLiteStatement createNewStatement() {
//获取前边创建的sql语句
String query = createQuery();
//最终去到SQLiteDatabase.compileStatement()里创建SQLiteStatement
return mDatabase.compileStatement(query);
}

优缺点

  • 优点:
    • 使用简单,能友好的支持Paging(后续介绍)
  • 缺点:
    • 生成的类会增大包体积,当然值不值得就得看ROI了。

性能方面的问题暂不做分析。

参考文章