随着今年RXjava Rxandroid的越来越火爆,一个响应式的数据库SqlBrite也被我们传说中的巨人,杰克大神放出,他基于RX观察者模式,来对我们原声的数据库进行操作,没有隐藏API,对于喜欢写sql语句的同学无非是比较不错的,
本文介绍下,在原生的sqllite中引入sqlbrite 操作数据库,先看下demo预览,
一个简单的界面,我们用数据库初始化了几个person,是不是看出来点什么端倪,
好吧,我们继续,
我们在app初始化的时候,用sqlite建立了数据库,以及我们的person表
这里的操作全部是原始的api操作大家都非常熟悉的
public class ATDbOpenHelper extends SQLiteOpenHelper {
public ATDbOpenHelper(Context context) {
super(context, ATDbConstant.AT_DB_NAME, null, ATDbConstant.AT_DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(ATDb.PersonTable.CREATE);
addSamePerson(db);
}
private void addSamePerson(SQLiteDatabase db) {
Person person = new Person();
person.setAge(35);
person.setName("陈冠希");
db.insert(ATDb.PersonTable.TABLE_NAME, null, ATDb.PersonTable.toContentValues(person));
person = new Person();
person.setAge(28);
person.setName("张柏芝");
db.insert(ATDb.PersonTable.TABLE_NAME, null, ATDb.PersonTable.toContentValues(person));
person = new Person();
person.setAge(23);
person.setName("蔡依林");
db.insert(ATDb.PersonTable.TABLE_NAME, null, ATDb.PersonTable.toContentValues(person));
person = new Person();
person.setAge(26);
person.setName("小S");
db.insert(ATDb.PersonTable.TABLE_NAME, null, ATDb.PersonTable.toContentValues(person));
person = new Person();
person.setAge(27);
person.setName("洪文安");
db.insert(ATDb.PersonTable.TABLE_NAME, null, ATDb.PersonTable.toContentValues(person));
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
接下来看下我们的DB对象
public class ATDb {
public ATDb() {
}
public static abstract class PersonTable {
// 表名
public static final String TABLE_NAME = "person";
// 表字段
public static final String ID = "_id";
public static final String COLUMN_NAME = "name";
public static final String COLUME_AGE = "age";
// 建表语句
public static final String CREATE =
"CREATE TABLE "
+ TABLE_NAME
+ " ("
+ ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ COLUMN_NAME + " TEXT NOT NULL,"
+ COLUME_AGE + " INT,"
+ "UNIQUE (" + COLUMN_NAME + ") ON CONFLICT REPLACE"
+ " ); ";
// 对象转字段,放入表中
public static ContentValues toContentValues(Person person) {
ContentValues values = new ContentValues();
values.put(COLUMN_NAME, person.getName());
values.put(COLUME_AGE, person.getAge());
return values;
}
// 响应式的查询,根据表中的row生成一个对象
static Func1<Cursor, Person> PERSON_MAPPER = new Func1<Cursor, Person>() {
@Override
public Person call(Cursor cursor) {
Person person = new Person();
String name = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME));
person.setName(name);
int age = cursor.getInt(cursor.getColumnIndexOrThrow(COLUME_AGE));
person.setAge(age);
return person;
}
};
}
}
这里依然没有什么变化,就是根据官方的demo,我们多了一个响应式的查询,mapper,这个mapper参数一会需要放到sqlbrite给我们提供的数据库对象中,
下面是数据库的DbManager,里面包含了sqlbrite给我们提供的上帝数据库,britedatebase
public class ATDbManager {
private static final String TAG = "ATDbManager";
// rx响应式数据库,
private BriteDatabase briteDatabase;
public ATDbManager(Context context) {
ATDbOpenHelper dbOpenHelper;
// sqlbrite 初始化,构造出响应式数据库,添加log
SqlBrite sqlBrite;
sqlBrite = SqlBrite.create(new SqlBrite.Logger() {
@Override
public void log(String message) {
Logger.wtf(TAG, "log: >>>>" + message);
}
});
// 原生的sqllitehelper 用来建立数据库和数据表,以及构造,rx响应式数据库
dbOpenHelper = new ATDbOpenHelper(context);
// 执行slqbirte 构造数据库的语句
briteDatabase = sqlBrite.wrapDatabaseHelper(dbOpenHelper, Schedulers.io());
briteDatabase.setLoggingEnabled(true);
}
public Observable<List<Person>> queryPerson() {
return briteDatabase
.createQuery(ATDb.PersonTable.TABLE_NAME, "SELECT * FROM " + ATDb.PersonTable.TABLE_NAME)
.mapToList(ATDb.PersonTable.PERSON_MAPPER);
}
public Observable<List<Person>> queryPersonByName(String name) {
return briteDatabase.createQuery(ATDb.PersonTable.TABLE_NAME, "SELECT * FROM "
+ ATDb.PersonTable.TABLE_NAME
+ " WHERE "
+ ATDb.PersonTable.COLUMN_NAME
+ " = ?"
, name)
.mapToList(ATDb.PersonTable.PERSON_MAPPER)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
public long addPerson(Person person) {
return briteDatabase.insert(ATDb.PersonTable.TABLE_NAME, ATDb.PersonTable.toContentValues(person));
}
public int deletePersonByName(final String name) {
return briteDatabase.delete(ATDb.PersonTable.TABLE_NAME, ATDb.PersonTable.COLUMN_NAME + "=?", name);
}
}
到这里,所有的数据库相关类全部介绍完毕,你会发现,sqlbrite不是一个数据库框架,他依然需要让你自己写sql语句来创建数据库查询,就是查询的等操作,采用了RX的方式来完成,这样的好处,就是我们在展示列表的时候,增删改查后,Sqlbrite都会自动的调用查询,来改变你传入列表的数据,不像我们以前的那种,比删除了一个人,你要更新列表,你需要重新queery person表然后 adapter notity,用sqlbrite可以不用这样做,
我们看下我们的activity中如何做,
//查询的时候,rx直接返回了当前数据的所有数据
private void queryPerson() {
Observable<List<Person>> listObservable = dbManager.queryPerson();
listObservable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Person>>() {
@Override
public void onCompleted() {
this.unsubscribe();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<Person> persons) {
Logger.e(TAG, "onNext: >>>>>" + persons.size() + persons.toString());
dataForRecylerView.clear();
dataForRecylerView.addAll(persons);
personAdapter.notifyDataSetChanged();
}
});
}
删除,操作,修改操作 在操作完毕后都会触发,查询,
以删除为例;
@OnClick(R.id.tv_add)
void addPerson() {
String personName = nameInput.getText().toString();
String personAge = ageInput.getText().toString();
if (TextUtils.isEmpty(personAge)) {
Snackbar.make(fab, "请输入年龄!", Snackbar.LENGTH_SHORT).show();
} else if (TextUtils.isEmpty(personName)) {
Snackbar.make(fab, "请输入姓名!", Snackbar.LENGTH_SHORT).show();
} else {
// 调用add person
Person addPerson = new Person();
addPerson.setAge(Integer.valueOf(personAge));
addPerson.setName(personName);
long state = dbManager.addPerson(addPerson);
if (state > 0) {
Snackbar.make(fab, "添加" + personName + "成功", Snackbar.LENGTH_SHORT).show();
}
// tips 没有调用查询语句,rxjava根据表数据的变化,会输出新的数据
}
}
执行完毕删除后,我们看下log日志,
所以我们刚才的删除代码,执行了db的delete语句并没有执行重新查询,列表会自动刷新.
想看源码分析和rx源码的同学,请佛咯github的杰克大神,SqlBirite源码链接
SqlBrite源码
最后奉上,demo的源码,欢迎拍砖!!
完整demo