一个响应式的数据库框架SQLBrite

随着今年RXjava Rxandroid的越来越火爆,一个响应式的数据库SqlBrite也被我们传说中的巨人,杰克大神放出,他基于RX观察者模式,来对我们原声的数据库进行操作,没有隐藏API,对于喜欢写sql语句的同学无非是比较不错的。

原文地址:http://blog.csdn.net/givemeacondom/article/details/51603428
本文介绍下,在原生的sqllite中引入sqlbrite 操作数据库,先看下demo预览
enter image description here

一个简单的界面,我们用数据库初始化了几个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对象:

 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可以不用这样做:

//查询的时候,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日志:
enter image description here
enter image description here
所以我们刚才的删除代码,执行了db的delete语句并没有执行重新查询,列表会自动刷新.
SQLBrite源码