20180502_从零开始的android持久库room其一

Room是android的一个持久化库,SQLite的抽象层,便于使用。推荐用Room替代SQLite。

[TOC]

引入room库

在project的gradle中加入google仓库

1
2
3
4
5
6
allprojects {
repositories {
jcenter()
google()
}
}

在app的gradle中加入room依赖

其中最后3个是用来支持rxjava2的,方便使用

1
2
3
4
5
6
7
8
9
dependencies {
// Room (use 1.1.0-beta3 for latest beta)
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
// RxJava support for Room (use 1.1.0-beta3 for latest beta)
implementation "android.arch.persistence.room:rxjava2:1.0.0"
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation "io.reactivex.rxjava2:rxjava:2.1.13"
}

初始化

Application中初始化数据库,记得在AndroidManifest.xml中配置App

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
27
28
public class App extends Application {

private static App instance;
private static AppDatabase db;

@Override
public void onCreate() {
super.onCreate();

instance = this;

initDb();
}

private void initDb() {
// 这里初始化room
db = Room.databaseBuilder(this,
AppDatabase.class, "database-name").build();
}

public static App getInstance() {
return instance;
}

public static AppDatabase getDb() {
return db;
}
}

Room的3大组件

  1. Database 数据库
  2. Entity 实体类
  3. DAO 数据访问对象

db

概念不是很难,直接看代码更加方便

1
2
3
4
@Database(entities = {Student.class}, version = 1) // 数据库注解,必须。entities指定实体类,version指定数据库版本
public abstract class AppDatabase extends RoomDatabase {
public abstract StudentDAO studentDao();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Entity // 实体类注解,必须
public class Student {
@PrimaryKey(autoGenerate = true) // 主键, autoGenerate表示自增长
private long uid;

@ColumnInfo(name = "first_name") // name指定的是表的字段名
private String firstName;

@ColumnInfo(name = "last_name")
private String lastName;

private int age; // 可以不指定ColumnInfo,那么表的字段名和属性名一致

// ... get set略
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Dao
public interface StudentDAO {
@Query("SELECT * FROM student")
Single<List<Student>> getAll();

@Query("SELECT * FROM student WHERE uid IN (:ids)")
Single<List<Student>> loadAllByIds(int[] ids);

@Query("SELECT * FROM student WHERE uid = :id")
Single<Student> findById(int id);

@Query("SELECT * FROM student WHERE first_name LIKE :first AND "
+ "last_name LIKE :last LIMIT 1")
Maybe<Student> findByName(String first, String last);

@Insert
List<Long> insertAll(Student... students);

@Update
void update(Student student);

@Delete
void delete(Student student);
}

数据访问(增删查改)

Insert

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
27
Student s = new Student();
s.setFirstName(firstName);
s.setLastName(lastName);
s.setAge(ageInt);

Callable<List<Long>> callable = () -> App.getDb().studentDao().insertAll(s);
Single.fromCallable(callable)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Long>>() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onSuccess(List<Long> longs) {
Log.i(TAG, String.format("onSuccess: insert success ids = %s", Arrays.toString(longs.toArray())));
Snackbar.make(et_first_name, "add student success", Snackbar.LENGTH_SHORT).show();
}

@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: insert error", e);
Snackbar.make(et_first_name, "add student fail", Snackbar.LENGTH_SHORT).show();
}
});

Delete

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
final Student s = studentList.get(position);
Action action = () -> App.getDb().studentDao().delete(s);

Completable.fromAction(action)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onComplete() {
Log.i(TAG, String.format("onComplete: delete student success id = %d", s.getUid()));
Snackbar.make(rv_list, "delete student success", Snackbar.LENGTH_SHORT).show();
}

@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: delete student fail", e);
Snackbar.make(rv_list, "delete student fail", Snackbar.LENGTH_SHORT).show();
}
});
}
});

Select

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
App.getDb().studentDao().getAll()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<Student>>() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onSuccess(List<Student> students) {
Log.i(TAG, String.format("onSuccess: students.size = %d", students.size()));
studentList.addAll(students);
adapter.notifyDataSetChanged();
}

@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: get all student error", e);
Snackbar.make(rv_list, "select student fail", Snackbar.LENGTH_SHORT).show();
}
});

Update

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
27
28
29
30
31
32
33
34
35
36
Action action = () -> {
Student s = new Student();
s.setUid(idInt);
if (!TextUtils.isEmpty(firstName)) {
s.setFirstName(firstName);
}
if (!TextUtils.isEmpty(lastName)) {
s.setLastName(lastName);
}
if (!TextUtils.isEmpty(age)) {
s.setAge(ageInt);
}
App.getDb().studentDao().update(s);
};

Completable.fromAction(action)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {

}

@Override
public void onComplete() {
Log.i(TAG, "onComplete: update student success");
Snackbar.make(et_id, "update student success", Snackbar.LENGTH_SHORT).show();
}

@Override
public void onError(Throwable e) {
Log.e(TAG, "onError: update student fail", e);
Snackbar.make(et_id, "update student fail", Snackbar.LENGTH_SHORT).show();
}
});

到这里,我们已经可以简单的增删查改数据库了。

注意事项

遇到下面的这个警告,说的是找不到地方导出schema

1
警告: Schema export directory is not provided to the annotation processor so we cannot export the schema. You can either provide `room.schemaLocation` annotation processor argument OR set exportSchema to false.

解决方案

在app的gradle文件中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
android {
// 略
defaultConfig {
// 略

// for room, 这里添加room的schemas导出地点
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
// 略
}

源码地址

AndroidRoomStudy

参考文章

android room

Fork me on GitHub