Realm的异步操作
在上一篇中使用了Realm的事务操作,实现了数据的增删改查。但是在执行增删改后,我们没法知道,数据是否发生改变了。反正我个人是比较菜,没找到啥方法能获取到数据是否发生改变。还好Realm本身支持异步操作并带有回调监听。使我又找到了学习的信心,然后实践了一下。
Realm的异步任务(增、删、改)
根据参考的资料来看,使用一个异步操作是挺简单的。因为步骤基本都是死的。基本步骤如下:
- 1.声明一个全局变量(为啥用全局变量,因为如果我想要在界面销毁时,同时取消未完成的异步任务我只能这吗做!):
private RealmAsyncTask insertTask,updataTask,deleteTask;//异步添加任务
- 2.创建异步任务:
创建RealmAsyncTask有四种方法,当然了它们都是重载方法。用哪个就看是啥需求了。
这里与带三个参数的方法为例,我们来看一下这三个参数都是干嘛的。
RealmAsyncTask task = realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//执行异步操作-->执行线程子线程
}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
//操作成功-->执行线程主线程
}
}, new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
//操作失败-->执行线程主线程
}
});
因为这三个参数都是接口的实现类同时还都是匿名内部类,所以还可以使用Lambda表达式进行一下代码的简化。于是代码就变成了这样(如果不使用retrolambda插件的话,要注意一下乱码的问题)。
RealmAsyncTask task = realm
.executeTransactionAsync(
realm1 -> Log.i("子线程", "执行异步操作!"),
() -> Log.i("主线程", "操作成功!"),
error -> Log.i("主线程", "操作失败!"));
- 3.在界面销毁的时候,取消未完成的异步任务
容我大胆的瞎说一下,这个跟退出界面后关闭子Thread和关闭动画(动画内部也是使用线程来实现的)的原理一样,都是为了防止内存泄漏。于是便在Activity或者Fragment的onDestory()方法中取消了未完成的异步任务。代码如下:
@Override
protected void onDestroy() {
cancelTask(insertTask);
cancelTask(updataTask);
cancelTask(deleteTask);
realm.close();
super.onDestroy();
}
private void cancelTask(RealmAsyncTask task){
if (task!=null&&!task.isCancelled()){
task.cancel();
}
}
Realm的异步任务(查询)
到了查询这就不能用上面的方法了,它有自己单独的方法。
- 1.全查询
RealmResults<Food> foods = realm.where(Food.class).findAllAsync();
foods.addChangeListener(new RealmChangeListener<RealmResults<Food>>() {
@Override
public void onChange(RealmResults<Food> element) {
//查询结束
}
});
- 2.条件查询并返回第一个结果
Food food = realm.where(Food.class).equalTo("name","A").findFirstAsync();
food.addChangeListener(new RealmChangeListener<RealmModel>() {
@Override
public void onChange(RealmModel element) {
//查询结束
}
});
例子中的增删改查操作
1、异步增
/**
* 添加数据
*/
@Override
public void insertDataToRealm(final Food food) {
insertTask = realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {//执行异步操作
Log.w("insertDataToRealm", "execute: ");
Log.i("线程", Thread.currentThread().getName());
realm.copyToRealm(food);
}
}, new Realm.Transaction.OnSuccess() {//操作成功
@Override
public void onSuccess() {
Toast.makeText(AsyncActivity.this,"添加成功!",Toast.LENGTH_SHORT).show();
Log.i("insertDataToRealm", "onSuccess: ");
Log.i("线程", Thread.currentThread().getName());
selectAllDataFromRealm();
}
}, new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
Log.d("线程", Thread.currentThread().getName());
Log.d("onError", error.getMessage());
}
});
}
2、异步删
/**
* 删除数据
* @param foodName
*/
@Override
public void deleteDataToRealm(final String foodName) {
deleteTask = realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//条件查询
Food food = realm.where(Food.class).equalTo("name",foodName).findFirst();
food.deleteFromRealm();//删除数据
}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
Toast.makeText(AsyncActivity.this,"删除成功!",Toast.LENGTH_SHORT).show();
selectAllDataFromRealm();
}
});
}
3、异步改
/**
* 更新数据
* @param foodName
*/
@Override
public void updataToRealm(final String foodName , final double price) {
updataTask = realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
//条件查询
Food food = realm.where(Food.class).equalTo("name",foodName).findFirst();
food.setPrice(price);//更改价格
}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
selectAllDataFromRealm();
Toast.makeText(AsyncActivity.this,"修改成功!",Toast.LENGTH_SHORT).show();
}
});
}
4、异步查
/**
* 异步全查询
*/
private void selectAllDataFromRealm(){
foods = realm.where(Food.class).findAllAsync();
foods.addChangeListener(new RealmChangeListener<RealmResults<Food>>() {
@Override
public void onChange(RealmResults<Food> element) {
Log.d("selectAllDataFromRealm", "查询到结果");
Log.i("线程", Thread.currentThread().getName());
List<Food> result = realm.copyFromRealm(foods);
if (result.size() == 0){
Log.d("结果集", "没有数据");
return;
}
for (Food food : result){
Log.d("结果集", "------------------------------");
Log.w("类别", food.getType());
Log.w("名称", food.getName());
Log.w("价格", food.getPrice()+"");
}
if (foods.isLoaded()){
foods.removeChangeListeners();
}
}
});
}
使用RealmBaseAdapter
使用起来需添加依赖:
compile 'io.realm:android-adapters:1.4.0'
这里我用了RxJava1(RxJava)来结合Realm来执行异步查询,因为Realm支持RxJava。所以又添加了两个依赖:
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
- 1.创建适配器
/**
* Author LYJ
* Created on 2017/2/23.
* Time 16:00
*/
public class TestAdapter extends RealmBaseAdapter<Food> implements ListAdapter {
public TestAdapter(@NonNull Context context, @Nullable OrderedRealmCollection<Food> data) {
super(context, data);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
viewHolder = new ViewHolder(convertView);
viewHolder.name = ButterKnife.findById(convertView,R.id.name);
viewHolder.price = ButterKnife.findById(convertView,R.id.price);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
Food food = adapterData.get(position);
viewHolder.name.setText(food.getName());
viewHolder.price.setText(String.valueOf(food.getPrice()));
return convertView;
}
static class ViewHolder {
@BindView(R.id.name)
TextView name;
@BindView(R.id.price)
TextView price;
ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}
- 2.查询数据后加载数据
/**
* 加载数据
*/
private void add() {
realm.where(Food.class)
.findAllAsync()
.asObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(foods -> {
listview.setAdapter(new TestAdapter(context,foods));
});
}