从网络加载,在UI上显示,并使用RxJava

时间:2017-02-21 03:28:29

标签: android database multithreading rx-java rx-android

我现在正致力于从网络获取数据的任务,在UI上显示,并将数据保存到本地数据库以供日后使用。目前我做的如下:

//Cloud loading
Observable<MyModel> loadDataFromCloud();

//Database
Observable<MyModel> saveDataToDisk(MyModel myModel);

//Load data
loadDataFromCloud()
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .flatMap(new Func1<MyModel, Observable<MyModel>>() {
    @Override
    public Observable<MyModel> call(MyModel myModel) {
      return saveDataToDisk(myModel);
    }
  })
  .subscribe(new Subscriber<MyModel>() {
    @Override
    public void onCompleted() {

    }

    @Override
    public void onError(Throwable e) {
      //exception handling
    }

    @Override
    public void onNext(MyModel myModel) {
      //bind myModel to UI
    }
  });

这种方法工作正常,但由于数据模型变得越来越复杂,数据库变得越来越大,因此它不再高效,因为所有数据库事务现在都在主线程上执行,UI需要等到完成交易以获得数据。

我现在正在改变这种新方法:

//A Singleton
Scheduler scheduler = Schedulers.from(Executors.newSingleThreadExecutor());

//Load data
loadDataFromCloud()
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .flatMap(new Func1<MyModel, Observable<MyModel>>() {
    @Override
    public Observable<MyModel> call(MyModel myModel) {
      try {
        //bind myModel to UI
        return Observable.just(s);
      } catch(Exception e) {
        return Observable.error(e)
      }
    }
  })
  .observeOn(scheduler)
  .flatMap(new Func1<MyModel, Observable<MyModel>>() {
    @Override
    public Observable<MyModel> call(MyModel myModel) {
      return saveDataToDisk(myModel);
    }
  })
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(new Subscriber<MyModel>() {
    @Override
    public void onCompleted() {

    }

    @Override
    public void onError(Throwable e) {
      //exception handling
    }

    @Override
    public void onNext(MyModel myModel) {
      //do nothing
    }
  });

我使用Schedulers.from(Executors.newSingleThreadExecutor())来确保所有数据库事务都是线程安全的。

我有一些问题:

  1. 使用Schedulers.from(Executors.newSingleThreadExecutor())确保所有数据库事务都是线程安全的是正确的方法吗?
  2. 是否有更好的方法来实现这一目标,因为上一次onNext()无所事事似乎是不明智的
  3. 使用RxJava,我们可以在两个不同的线程上同时开始执行两项任务(在UI上显示并保存到磁盘)
  4. 我已经搜索了一段时间并收到了一些像this one这样的文章,但他们没有直接解决我的问题。

1 个答案:

答案 0 :(得分:1)

首先,首先,你在主线程上进行IO操作,这是一个不好的做法,在android中它可以导致anr。

  1. 基本上它应该同步,但只要您在应用中使用相同的Scheduler,否则您将为每个订阅此可观察对象创建新线程。但是,有些奇怪的是,因为DB操作通常是线程安全的。
  2. 在您的方案中,您希望显示ui,并且可以saveDataToDisk()并行而不等待它,因此您可以使用doOnNext运算符在不同的可观察对象上启动保存操作(您不需要#39; t关心其结果)而不遵守它的结果。
  3. 总而言之,你应该这样:

    loadDataFromCloud()
       .doOnNext(data - > saveDataToDisk().subscribeOn(Schedulers.io()))
       .subscribeOn(Schedulers.io())
       .observeOn(AndroidSchedulers.mainThread())
       .subscribe(data -> //uodate your ui) 
    
    Dan Lew的帖子是一个很好的例子,你应该按照那里的例子。