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

本文介绍下,在原生的sqllite中引入sqlbrite 操作数据库,先看下demo预览,


Android_Sqlbrite入门使用_ide

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


Android_Sqlbrite入门使用_Sqlbrite响应式数据库_02


Android_Sqlbrite入门使用_Sqlbrite响应式数据库_03

所以我们刚才的删除代码,执行了db的delete语句并没有执行重新查询,列表会自动刷新.

想看源码分析和rx源码的同学,请佛咯github的杰克大神,SqlBirite源码链接 
SqlBrite源码

最后奉上,demo的源码,欢迎拍砖!!

完整demo