一、什么是SqlBrite
对 Android 系统的SQLiteOpenHelper
和 ContentResolver
的轻量级封装,配合Rxjava使用。
github地址: https://github.com/square/sqlbrite
ps: 2017年3月15号为止,还不支持Rxjava2,有点遗憾。
二、导包和初始化
在module的builde.gradle依赖加入以下,如果你没导入Rxjava,那么他会自动导入:
compile 'com.squareup.sqlbrite:sqlbrite:1.1.1'
- 1
创建一个 SqlBrite 对象,该对象是该库的入口:
SqlBrite sqlBrite = new SqlBrite.Builder().build();
- 1
通过SQLiteOpenHelper实例和调度创建BriteDatabase,由于数据库操作是个耗时操作,不建议在 UI 线程中执行的,所以这里可以添加调度器进行线程的控制Scheduler ,一般指定 Schedulers.io() 。
//根据SQLiteOpenHelper和Scheduler来创建BriteDatabase,指定调度器为io操作
BriteDatabase db = sqlBrite.wrapDatabaseHelper(helper, Schedulers.io());
- 1
- 2
- 3
如果是使用 ContentProvider 的话,需要使用 ContentResolver
来创建一个 BriteContentResolver 对象:
BriteContentResolver resolver = sqlBrite.wrapContentProvider(contentResolver, Schedulers.io());
Observable<Query> query = resolver.createQuery(/*...*/);
- 1
- 2
三、 数据库操作
增删改查基本用法。
查询操作
BriteDatabase.createQuery方法类似于SQLiteDatabase.rawQuery,但是它需要一个附加的表参数来监听更改。
Subscribe 返回的Observable ,它将立即通知Query运行。
Observable<Query> users = db.createQuery("users", "SELECT * FROM users");
users.subscribe(new Action1<Query>() {
@Override public void call(Query query) {
Cursor cursor = query.run();
// TODO parse data...
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
与传统的rawQuery不同,对指定表的更新将触发其他通知,只要您保持订阅Observable,
意思就是,当您插入,更新或删除数据时,任何subscribed的查询会立即更新新的数据。
增加插入操作
插入方法调用的就是SqlDataBase的插入方法,这个没什么好说的了。
//根据todo_list表的id,插入数据到todo_item表,
db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
.listId(groceryListId)
.description("Beer")
.build());
- 1
- 2
- 3
- 4
- 5
修改更新操作
有5个参数
- 表名
- ContentValues
- 冲突解决方案,一般为0就行
- where条件字句
- where 可变参数
例如官方栗子里面的:
//更新数据库
db.update(TodoItem.TABLE, new TodoItem.Builder().complete(newValue).build(),
TodoItem.ID + " = ?", String.valueOf(event.id()));
}
- 1
- 2
- 3
- 4
删除操作
从表中删除指定的行,有三个参数:
- 表名
- where条件语句
- where可变参数
db.delete(TodoItem.TABLE,"");
- 1
- 2
删除表就执行sql语句了要。
四、其他使用注意
在下面的例子中,重用了BriteDatabase对象“db”作为插入。所有插入,更新或删除操作都必须通过此对象才能正确通知subscribers。
Unsubscribe取消订阅退回对应的subscriber,可以停止获取更新。
final AtomicInteger queries = new AtomicInteger();
Subscription s = users.subscribe(new Action1<Query>() {
@Override public void call(Query query) {
queries.getAndIncrement();
}
});
System.out.println("Queries: " + queries.get()); // Prints 1
db.insert("users", createUser("jw", "Jake Wharton"));
db.insert("users", createUser("mattp", "Matt Precious"));
s.unsubscribe();
db.insert("users", createUser("strong", "Alec Strong"));
System.out.println("Queries: " + queries.get()); // Prints 3
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
使用transactions可防止数据的大量更改导致subscribers频繁调用。
final AtomicInteger queries = new AtomicInteger();
users.subscribe(new Action1<Query>() {
@Override public void call(Query query) {
queries.getAndIncrement();
}
});
System.out.println("Queries: " + queries.get()); // Prints 1
Transaction transaction = db.newTransaction();
try {
db.insert("users", createUser("jw", "Jake Wharton"));
db.insert("users", createUser("mattp", "Matt Precious"));
db.insert("users", createUser("strong", "Alec Strong"));
transaction.markSuccessful();
} finally {
transaction.end();
}
System.out.println("Queries: " + queries.get()); // Prints 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
ps: 可以用try-with-resources语法使用transaction。可以简化代码,例如:
try (BriteDatabase.Transaction transaction = db.newTransaction()){
db.insert("users", createUser("jw", "Jake Wharton"));
db.insert("users", createUser("mattp", "Matt Precious"));
db.insert("users", createUser("strong", "Alec Strong"));
transaction.markSuccessful();
}
- 1
- 2
- 3
- 4
- 5
- 6
由于查询只是常规的RxJava Observable对象,运算符也可以用于控制向订阅者发送通知的频率。
users.debounce(500, MILLISECONDS).subscribe(new Action1<Query>() {
@Override public void call(Query query) {
// TODO...
}
});
- 1
- 2
- 3
- 4
- 5
- 6
四、官方demo讲解
官方的demo是一个记事本备忘录的功能的一个app,名为todo。 谷歌的栗子也是这个todo。
导入了官方的demo,可以发现,里面有利用的Dagger2、AutoValue、ButterKnife等等这些包。对这些知识还不会用的朋友请先看:
Dagger2:
Android快速依赖注入框架Dagger2使用1
AutoValue:
Android AutoValue使用和扩展库
ButterKnife: ButterKnife8.5.1 使用方法教程总结
我们应该怎么分析一个app呢? 我一般的习惯是
- 程序跑起来
- 看导包
- 看manifest
- 看application
- 看入口activity
然后就一个页面一个页面地看下去
目录
db目录存放数据库相关的类和bean
ui目录放view: activity和fragment和适配器
外层是Dagger2: Component和Module和Application
整体流程
利用Dagger2在ListsFragmnet、ItemsFragment、NewItemFragment、NewListFragment进行注入,
AppModule提供单例的Application,TodoModule里面包括了DbModule。
@Singleton
@Component(modules = TodoModule.class)
public interface TodoComponent {
void inject(ListsFragment fragment);
void inject(ItemsFragment fragment);
void inject(NewItemFragment fragment);
void inject(NewListFragment fragment);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在DbModule中进行了DbOpenHelper、SqlBrite、BriteDatabase的初始化,提供注入。
@Module
public final class DbModule {
//初始化提供SQLiteOpenHelper
@Provides
@Singleton
SQLiteOpenHelper provideOpenHelper(Application application) {
return new DbOpenHelper(application);
}
//初始化提供SqlBrite
@Provides
@Singleton
SqlBrite provideSqlBrite() {
return SqlBrite.create(new SqlBrite.Logger() {
@Override
public void log(String message) {
Timber.tag("Database").v(message);
}
});
}
//初始化提供BriteDatabase
@Provides
@Singleton
BriteDatabase provideDatabase(SqlBrite sqlBrite, SQLiteOpenHelper helper) {
BriteDatabase db = sqlBrite.wrapDatabaseHelper(helper, Schedulers.io());
db.setLoggingEnabled(true);
return db;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
DbOpenHelper进行了表的创建和插入对应的数据:
final class DbOpenHelper extends SQLiteOpenHelper {
private static final int VERSION = 1;
//创建todo_list表的语句
private static final String CREATE_LIST = ""
+ "CREATE TABLE " + TodoList.TABLE + "("
+ TodoList.ID + " INTEGER NOT NULL PRIMARY KEY,"
+ TodoList.NAME + " TEXT NOT NULL,"
+ TodoList.ARCHIVED + " INTEGER NOT NULL DEFAULT 0"
+ ")";
//创建todo_item表的语句
private static final String CREATE_ITEM = ""
+ "CREATE TABLE " + TodoItem.TABLE + "("
+ TodoItem.ID + " INTEGER NOT NULL PRIMARY KEY,"
+ TodoItem.LIST_ID + " INTEGER NOT NULL REFERENCES " + TodoList.TABLE + "(" + TodoList.ID + "),"
+ TodoItem.DESCRIPTION + " TEXT NOT NULL,"
+ TodoItem.COMPLETE + " INTEGER NOT NULL DEFAULT 0"
+ ")";
//创建 单列索引,加速查询
private static final String CREATE_ITEM_LIST_ID_INDEX =
"CREATE INDEX item_list_id ON " + TodoItem.TABLE + " (" + TodoItem.LIST_ID + ")";
//构造器,创建数据库
public DbOpenHelper(Context context) {
super(context, "todo.db", null /* factory */, VERSION);
}
//创建数据库的时候回调
@Override
public void onCreate(SQLiteDatabase db) {
//创建对应的表和索引
db.execSQL(CREATE_LIST);
db.execSQL(CREATE_ITEM);
db.execSQL(CREATE_ITEM_LIST_ID_INDEX);
//插入数据到todo_list表,返回id
long groceryListId = db.insert(TodoList.TABLE, null, new TodoList.Builder()
.name("Grocery List")
.build());
//根据todo_list表的id,插入数据到todo_item表,
db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
.listId(groceryListId)
.description("Beer")
.build());
db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
.listId(groceryListId)
.description("Point Break on DVD")
.build());
db.insert(TodoItem.TABLE, null, new TodoItem.Builder()
.listId(groceryListId)
.description("Bad Boys 2 on DVD")
.build());
//下面的三列和上面的套路一样,就不贴代码了
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
这时候我就就知道应用创建了两个表: todo_list和todo_item,根据todo_list的id进行关联。就相当于todo_list表存放的是标题,todo_item存放的是所有的数据。
TodoList和TodoItem是bean类,使用了AutoValue进行bean类代码生成。
里面存放了表名、字段对应的常量,还有对应的数据获取。还有使用Builder用来生成ContentValues。
(这里贴出TodoList的代码,TodoItem的套路一样)
@AutoValue
public abstract class TodoList implements Parcelable {
public static final String TABLE = "todo_list";
public static final String ID = "_id";
public static final String NAME = "name";
public static final String ARCHIVED = "archived";
public abstract long id();
public abstract String name();
public abstract boolean archived();
//利用RXjava进行数据的获取,返回bean列表
public static Func1<Cursor, List<TodoList>> MAP = new Func1<Cursor, List<TodoList>>() {
@Override
public List<TodoList> call(final Cursor cursor) {
try {
List<TodoList> values = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
long id = Db.getLong(cursor, ID);
String name = Db.getString(cursor, NAME);
boolean archived = Db.getBoolean(cursor, ARCHIVED);
values.add(new AutoValue_TodoList(id, name, archived));
}
return values;
} finally {
cursor.close();
}
}
};
//构建器,用来生成ContentValues
public static final class Builder {
private final ContentValues values = new ContentValues();
public Builder id(long id) {
values.put(ID, id);
return this;
}
public Builder name(String name) {
values.put(NAME, name);
return this;
}
public Builder archived(boolean archived) {
values.put(ARCHIVED, archived);
return this;
}
public ContentValues build() {
return values; // TODO defensive copy?
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
接下来看回到Application初始化TodoComponent。供给Fragment进行注入。
public final class TodoApp extends Application {
private TodoComponent mainComponent;
@Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
}
mainComponent = DaggerTodoComponent.builder().todoModule(new TodoModule(this)).build();
}
public static TodoComponent getComponent(Context context) {
return ((TodoApp) context.getApplicationContext()).mainComponent;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
整个app就一个activity,其他都是Fragment。MainActivity利用了系统自带的布局进行初始化显示ListsFragment,
并且回调ListsFragment操作的接口。
public final class MainActivity extends FragmentActivity
implements ListsFragment.Listener, ItemsFragment.Listener {
// 设置内容为Listsfragment
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, ListsFragment.newInstance())
.commit();
}
}
//ListsFragment的item点击回调
@Override
public void onListClicked(long id) {
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left,
R.anim.slide_out_right)
.replace(android.R.id.content, ItemsFragment.newInstance(id))
.addToBackStack(null)
.commit();
}
//菜单的newList点击回调
@Override
public void onNewListClicked() {
NewListFragment.newInstance().show(getSupportFragmentManager(), "new-list");
}
/**
* 菜单的newItem点击回调
* @param listId 对应todo_list表的列的id
*/
@Override
public void onNewItemClicked(long listId) {
NewItemFragment.newInstance(listId).show(getSupportFragmentManager(), "new-item");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
ListsFragment为单例,是todo_list表的数据,在初始化时候回调onAttach进行Dagger2的注入、初始化ListsAdapter适配器、开启右上角的菜单。
布局主要是一个ListView用来显示TodoList表的数据。界面实现完毕进行设置标题、查询数据库。
public final class ListsFragment extends Fragment {
//回调到MainActivity的接口
interface Listener {
//列表点击
void onListClicked(long id);
//新建列表点击
void onNewListClicked();
}
//单例实现
static ListsFragment newInstance() {
return new ListsFragment();
}
@Inject
BriteDatabase db; //注入获取BriteDatabase
//使用ButterKnife获取View
@BindView(android.R.id.list)
ListView listView;
@BindView(android.R.id.empty)
View emptyView;
//回调接口
private Listener listener;
//适配器
private ListsAdapter adapter;
//Rxjava的订阅者,在离开界面进行接触订阅
private Subscription subscription;
//初始化时候进行Dagger2的注入
@Override
public void onAttach(Activity activity) {
if (!(activity instanceof Listener)) {
throw new IllegalStateException("Activity must implement fragment Listener.");
}
super.onAttach(activity);
//Dagger2的注入
TodoApp.getComponent(activity).inject(this);
//设置菜单
setHasOptionsMenu(true);
listener = (Listener) activity;
//初始化适配器
adapter = new ListsAdapter(activity);
}
//添加菜单为 NEW LIST
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
//点击菜单回调
MenuItem item = menu.add(R.string.new_list)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
listener.onNewListClicked();
return true;
}
});
MenuItemCompat.setShowAsAction(item, SHOW_AS_ACTION_IF_ROOM | SHOW_AS_ACTION_WITH_TEXT);
}
//创建Fragment的布局
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.lists, container, false);
}
//view创建完毕,开始绑定Butterknife、适配器
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
listView.setEmptyView(emptyView);
listView.setAdapter(adapter);
}
@OnItemClick(android.R.id.list)
void listClicked(long listId) {
listener.onListClicked(listId);
}
//界面显示完毕设置标题、查询数据库
@Override
public void onResume() {
super.onResume();
getActivity().setTitle("To-Do");
subscription = db.createQuery(ListsItem.TABLES, ListsItem.QUERY)
.mapToList(ListsItem.MAPPER) //映射到ListItem的MAPPER
.observeOn(AndroidSchedulers.mainThread())//设置订阅者在主线程进行
.subscribe(adapter);
}
@Override
public void onPause() {
super.onPause();
//界面隐藏解除订阅
subscription.unsubscribe();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
ListsAdapter作为数据的适配显示,实现了Rxjava的Action1
final class ListsAdapter extends BaseAdapter implements Action1<List<ListsItem>> {
private final LayoutInflater inflater;
private List<ListsItem> items = Collections.emptyList();
public ListsAdapter(Context context) {
this.inflater = LayoutInflater.from(context);
}
//在ListsFragment里面Rxjava查询数据库完毕,在这里更新适配器
@Override
public void call(List<ListsItem> items) {
this.items = items;
notifyDataSetChanged();
}
....(下面的就省略了)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
ListsItem是ListsFragment的数据list的bean,里面定义了一个查询语句,这个语句可能比较复杂,意思就是 根据todo_list的_id分组
,选择_id,name,todo_listd _id对应的todo_item的数量(Sql语句不懂的先去补习一下吧)。 还有一个MAPPER映射,Rxjava的处理把Cursor转换为ListsItem。
SELECT list._id, list.name, COUNT(item._id) as item_count
FROM todo_list AS list
LEFT OUTER JOIN todo_item AS item ON list._id = item.todo_list_id
GROUP BY list._id
- 1
- 2
- 3
- 4
- 5
ItemsFragment是todo_item表的数据,存放的是所有的item。
通过在ListsFragment中点击item的时候传递todo_list表的_id来,然后ItemFragmnet根据list的_id查询得到item显示,和查询数量和todo_list的nane作为标题。
基本套路和ListsFragmnet差不多。
ItemsFragmeng用到了Rxbinding,对listView的item点击进行监听,每点击一次就更新todo_item表对应的数据,就是备忘录的任务完成了的意思。
public final class ItemsFragment extends Fragment {
private static final String KEY_LIST_ID = "list_id";
//根据todo_list_id查询todo_item表的所有的数据
private static final String LIST_QUERY = "SELECT * FROM "
+ TodoItem.TABLE
+ " WHERE "
+ TodoItem.LIST_ID
+ " = ? ORDER BY "
+ TodoItem.COMPLETE
+ " ASC";
//根据todo_list_id查询todo_item表所有的数据的总数
private static final String COUNT_QUERY = "SELECT COUNT(*) FROM "
+ TodoItem.TABLE
+ " WHERE "
+ TodoItem.COMPLETE
+ " = "
+ Db.BOOLEAN_FALSE
+ " AND "
+ TodoItem.LIST_ID
+ " = ?";
//根据_id查询todo_list表的数据的name
private static final String TITLE_QUERY =
"SELECT " + TodoList.NAME + " FROM " + TodoList.TABLE + " WHERE " + TodoList.ID + " = ?";
public interface Listener {
void onNewItemClicked(long listId);
}
public static ItemsFragment newInstance(long listId) {
Bundle arguments = new Bundle();
arguments.putLong(KEY_LIST_ID, listId);
ItemsFragment fragment = new ItemsFragment();
fragment.setArguments(arguments);
return fragment;
}
@Inject
BriteDatabase db;
@BindView(android.R.id.list)
ListView listView;
@BindView(android.R.id.empty)
View emptyView;
private Listener listener;
private ItemsAdapter adapter;
private CompositeSubscription subscriptions; //可以组合多个subscriptions,便于解除订阅
private long getListId() {
return getArguments().getLong(KEY_LIST_ID);
}
@Override
public void onAttach(Activity activity) {
if (!(activity instanceof Listener)) {
throw new IllegalStateException("Activity must implement fragment Listener.");
}
super.onAttach(activity);
TodoApp.getComponent(activity).inject(this);
setHasOptionsMenu(true);
listener = (Listener) activity;
adapter = new ItemsAdapter(activity);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem item = menu.add(R.string.new_item)
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
listener.onNewItemClicked(getListId());
return true;
}
});
MenuItemCompat.setShowAsAction(item, SHOW_AS_ACTION_IF_ROOM | SHOW_AS_ACTION_WITH_TEXT);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.items, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
listView.setEmptyView(emptyView);
listView.setAdapter(adapter);
//监听Listview的点击,更新todo_item表的状态
RxAdapterView.itemClickEvents(listView) //
.observeOn(Schedulers.io())
.subscribe(new Action1<AdapterViewItemClickEvent>() {
@Override
public void call(AdapterViewItemClickEvent event) {
//取相反值
boolean newValue = !adapter.getItem(event.position()).complete();
//更新数据库
db.update(TodoItem.TABLE, new TodoItem.Builder().complete(newValue).build(),
TodoItem.ID + " = ?", String.valueOf(event.id()));
}
});
}
@Override
public void onResume() {
super.onResume();
//得到todo_list表对应的_id
String listId = String.valueOf(getListId());
//创建订阅者
subscriptions = new CompositeSubscription();
//查询todo_item表的对应todo_list_id的总数
Observable<Integer> itemCount = db.createQuery(TodoItem.TABLE, COUNT_QUERY, listId) //
.map(new Func1<Query, Integer>() {
@Override
public Integer call(Query query) {
Cursor cursor = query.run();
try {
if (!cursor.moveToNext()) {
throw new AssertionError("No rows");
}
return cursor.getInt(0);
} finally {
cursor.close();
}
}
});
//根据_id查询todo_list表的数据的name
Observable<String> listName =
db.createQuery(TodoList.TABLE, TITLE_QUERY, listId).map(new Func1<Query, String>() {
@Override
public String call(Query query) {
Cursor cursor = query.run();
try {
if (!cursor.moveToNext()) {
throw new AssertionError("No rows");
}
return cursor.getString(0);
} finally {
cursor.close();
}
}
});
//取得对应list的名字和todo_item表对应的数量数量作为标题。
subscriptions.add(
Observable.combineLatest(listName, itemCount, new Func2<String, Integer, String>() {
@Override
public String call(String listName, Integer itemCount) {
return listName + " (" + itemCount + ")";
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override
public void call(String title) {
getActivity().setTitle(title);
}
}));
//根据todo_list_id查询todo_item表的所有的数据,更新到适配器
subscriptions.add(db.createQuery(TodoItem.TABLE, LIST_QUERY, listId)
.mapToList(TodoItem.MAPPER)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(adapter));
}
@Override
public void onPause() {
super.onPause();
//解除订阅多个subscriptions
subscriptions.unsubscribe();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
好了,SqlBrite官方的demo基本功能就这样。