隨着今年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的源碼,歡迎拍磚!!