您的位置:首页 > 理论基础 > 计算机网络

Android 使用RxJava+Retrofit +Realm 组合加载数据 <读取缓存 显示 请求网络数据 缓存最新数据 更新界面>(二)

2016-07-22 16:20 966 查看
继续完善上次懵懵懂懂的流程.

原理还是一样的.不明白的看一看

Android 使用RxJava+Retrofit +Realm 组合加载数据 <读取缓存 显示 请求网络数据 缓存最新数据 更新界面>(一)

这次整合的是数据库Realm点击查看中文文档感兴趣的可以去看看.

使用Realm的原因是它和Retrofit一样.天生支持Rxjava,当然还有其他的,不过我没用过.

Realm配置 Applaction中 ,如果配置了多进程的话.最好是判断一下包名,防止调用多次

private void initRealm() {
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
.name("xxx.realm")
.schemaVersion(1)
.rxFactory(new RealmObservableFactory()) //默认Rxjava支持,貌似不写也可以
.deleteRealmIfMigrationNeeded()//测试使用,每次都删除原来的数据
//                .encryptionKey(key)
//                .modules(new MySchemaModule())
//                    .migration(migration)
.build();
Realm.setDefaultConfiguration(realmConfiguration);
}


Realm 配合Rxjava查询方法,官方文档配置

// Combining Realm, Retrofit and RxJava (Using Retrolambda syntax for brevity)
// Load all persons and merge them with their latest stats from GitHub (if they have any)
Realm realm = Realm.getDefaultInstance();
GitHubService api = retrofit.create(GitHubService.class);
realm.where(Person.class).isNotNull("username").findAllAsync().asObservable()
.filter(persons.isLoaded)
.flatMap(persons -> Observable.from(persons))
.flatMap(person -> api.user(person.getGithubUserName())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(user -> showUser(user));


请注意异步查询不会阻塞当前线程,如上代码会立即返回一个 RealmResults 实例。如果你想确定该 RealmResults 已经加载完成请使用 filter operator 和 RealmResults.isLoaded() 方法。通过判断 RealmResults 是否已经加载可以得知查询是否已经完成。

以上为官网文档的原话,不过根据我实际上使用来说.使用Realm.getDefaultInstance().asObservable()会永远不掉用onComplete()方法,这是一个坑,还挺深的,而且使用过程中,多次调用onNext(),这样就会导致在Subscriber.onNext()多次调用,也就是说,界面将会被刷新多次
如果想取一次数据,需要使用 filter/first()

查询代码

final Realm realm = Realm.getDefaultInstance();
Observable<RecommendHome> dataSourceFromDb = realm.where(RecommendHome.class).findFirstAsync()
.<RecommendHome>asObservable()
.filter(new Func1<RecommendHome, Boolean>() {
@Override
public Boolean call(RecommendHome recommendHome) {
LogUtils.w(TAG, "dataSource from realm");
return recommendHome.isLoaded();
}
})
.first()
.doOnCompleted(new Action0() {
@Override
public void call() {
if (realm == null && !realm.isClosed()) {
realm.close();
}
}
});


需要说明的是Realm有线程保护机制,不能多线程访问同一实例,它只能使用在创建他的线程中,根据官网文档说明异步查询不会阻塞当前线程,我也就相信了,也就是说 Rxjava 中很便捷的切换线程在这里就然并卵了

将查询和网络请求结合,这里我用到的还是之前提到的 concat 大体的意思就是将多个Observable发射的数据同到一个Subscriber中处理. 基于这个原理.修改
NetManager
类是同一个只是修改了其中的方法

public void getRecommendDataSource(Subscriber<RecommendHome> subscriber, boolean isConnection) {
final Realm realm = Realm.getDefaultInstance();
Observable<RecommendHome> dataSourceFromDb = realm.where(RecommendHome.class).findFirstAsync()
.<RecommendHome>asObservable()
.filter(new Func1<RecommendHome, Boolean>() {
@Override
public Boolean call(RecommendHome recommendHome) {
LogUtils.w(TAG, "dataSource from realm");
return recommendHome.isLoaded();
}
})
.first()
.doOnCompleted(new Action0() {
@Override
public void call() {
if (realm == null && !realm.isClosed()) {
realm.close();
}
}
});
Observable<RecommendHome> dataSourceFromNet = RetrofitManager.getWebApiService()
.getRecommendHomeDatas()
.doOnNext(new Action1<RecommendHome>() {
@Override
public void call(RecommendHome recommendHome) {
LogUtils.w(TAG, "save to db");
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
realm.copyToRealmOrUpdate(recommendHome);
realm.commitTransaction();
realm.close();
}
})
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
if (isConnection) {
Observable.concat(dataSourceFromDb, dataSourceFromNet).subscribe(subscriber);
} else {
dataSourceFromDb.subscribe(subscriber);
}
}


调用的时候直接在Activity/Fragment 中传入
Subscriber<T>
就可以了,这里的boolean参数是判断网络连接状态的,可有可无

Log如下

无网络状态

07-22 16:11:29.496 16479-16479: dataSource from realm
07-22 16:11:29.746 16479-16479: dataSource from realm
07-22 16:11:29.746 16479-16479: subscriber onNext
07-22 16:11:29.766 16479-16479: subscriber onCompleted


有网络状态

07-22 16:13:13.246 16479-16479: dataSource from realm
07-22 16:13:13.246 16479-16479: dataSource from realm
07-22 16:13:13.246 16479-16479: subscriber onNext
07-22 16:13:13.746 16479-19234: save to db
07-22 16:13:13.826 16479-16479: subscriber onNext
07-22 16:13:13.836 16479-16479: subscriber onCompleted


到这基本上就完成 读取数据 -> 显示 -> 请求网络数据 -> 缓存新数据 ->更新界面

就这样

—end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息