20180502_从零开始的android持久库room其一
程序员文章站
2024-03-17 13:56:34
...
20180502_从零开始的android持久库room其一
Room是android的一个持久化库,SQLite的抽象层,便于使用。推荐用Room替代SQLite。
引入room库
在project的gradle中加入google仓库
allprojects {
repositories {
jcenter()
google()
}
}
在app的gradle中加入room依赖
其中最后3个是用来支持rxjava2的,方便使用
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
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大组件
- Database 数据库
- Entity 实体类
- DAO 数据访问对象
概念不是很难,直接看代码更加方便
@Database(entities = {Student.class}, version = 1) // 数据库注解,必须。entities指定实体类,version指定数据库版本
public abstract class AppDatabase extends RoomDatabase {
public abstract StudentDAO studentDao();
}
@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略
}
@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
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
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
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
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
警告: 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文件中添加
android {
// 略
defaultConfig {
// 略
// for room, 这里添加room的schemas导出地点
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
// 略
}