2016-06-01 17 views
1

これはそうである:rxjavaを使用して複数のデータソースを処理する方法は?

Iは、ビジネスロジックのためのインターフェースをフェッチデータを提供するために、ドメイン層を有していて、私は2つのデータソースを有する:ローカルデータベースおよびリモートネットワーク。 DataRepository.getInstance().getUsers(); DataRepositoryで

  • 、2つの要因がある:

    1. 要求するすべてのユーザー:

      それは次のように動作 データがない場合、ローカルデータベースからすべてのユーザーをフェッチ

      • LocalDataSource.getUsers()この要求を無視します。データを保存したり、ローカルデータベースにそれを更新し、結果を送り返し、要求された、(ローカルデータベース内のデータが更新さを維持したデータの目的のために、あったとしても)当社のサーバーから最新のユーザーのリストを要求
      • RemoteDataSource.getUsers()

        public Observable<List<User>> getUsers() { 
            return Observable.create(new Observable.OnSubscribe<List<User>>() { 
             @Override 
             public void call(Subscriber<? super List<User>> subscriber) { 
              // 1. Request users from local database 
              List<User> localUsers = mLocalDataSource.getUsers(); 
              if (!localUsers.isEmpty()) { 
               subscriber.onNext(localUsers); 
              } 
              // 2. Request the latest user list from server 
              // Send a retrofit2 request 
              Call<List<User>> call = mRemoteDataSource.getUsers(); 
              try { 
               List<User> networkUsers = call.execute().body(); 
               mLocalDataSource.saveUsers(networkUsers); 
               subscriber.onNext(networkUsers); 
               subscriber.onCompleted(); 
              } catch (IOException e) { 
               subscriber.onError(e); 
              } 
             } 
            }); 
        } 
        

        は、今私はすでに、なぜやってSqlBriteとRetrofit2 RxAdaptersを使用していない、プロジェクトにrxjavaを使用することを考えて:私はDataRepositoryでこれを行うことにより、私の目標を達成することができることを知っている

    これはもっと便利なのですか? だから、LocalDataSource.getUsers()は今Observable<List<User>>を返し、そうRemoteDataSource.getUsers()はありません。

    LocalDataSource.java

    public Observable<User> getUsers() { 
        final String sqlQuery = String.format("SELECT * FROM %s", UserTable.TABLE_NAME); 
        return mDatabaseHelper.createQuery(UserTable.TABLE_NAME, sqlQuery) 
          .mapToList(new Func1<Cursor, User>() { 
           @Override 
           public User call(Cursor c) { 
            return UserTable.parseCursor(c); 
           } 
          }); 
    } 
    

    RemoteDataSource.java

    public Observable<List<User>> getUsers() { 
        return mRetrofitApi.users(); 
    } 
    

    質問:

    私は古いトリックで行った同じことを達成するためにDataRepository.getUsers()に何をすべきか?

    public Observable<List<User>> getUsers() { 
        Observable<List<User>> localUsers = mLocalDataSource.getUsers(); 
        Observable<List<User>> remoteUsers = mRemoteDataSource.getUsers() 
          .flatMap(new Func1<List<User>, Observable<User>>() { 
           @Override 
           public Observable<User> call(List<User> users) { 
            return Observable.from(users); 
           } 
          }) 
          .doOnNext(new Action1<User>() { 
           @Override 
           public void call(User user) { 
            mLocalDataSource.saveUser(user); 
           } 
          }) 
          .toList(); 
        // What should I return to make two observables both able to emit results to the Subscriber 
        return Observable.concat(localUsers, remoteUsers); // ??? 
    } 
    
  • 答えて

    3

    私はDataRepository.getUsersに()私は古いトリックで行った同じことを達成するために何をすべき?このような場合には

    、あなたはconcat使用することができます。

    public Observable<List<User>> getUsers() { 
        return Observable.concat(localUsers.first(), remoteUsers); 
    } 
    

    をしかし、それは、ローカルまたはリモートの結果が最初に来るかどうかは関係ありませんならば、あなたはmergeを使用することができます。

    public Observable<List<User>> getUsers() { 
        return Observable.merge(localUsers.first(), remoteUsers); 
    } 
    

    あなただけちょうど(速く1勝)1件の結果が必要な場合はさらに、あなたはambを使用することができます。

    public Observable<List<User>> getUsers() { 
        return Observable.amb(localUsers.first(), remoteUsers); 
    } 
    
    +0

    重複するユーザーオブジェクトは自動的に削除されますか?たとえば、User1は両方の場合に存在し、出力ストリームにUser1が1つだけ存在しますか? –

    +1

    @IlanthirayanParamanathanいいえ、そうではありません、 'concat'と' merge'は重複除外作業を行いません。 – Piasy

    +0

    私は、hasCode()、equal(Object obj)メソッドをオーバーライドする必要があるUser Modelクラスで達成するために、distinct()を使用して重複を排除する方法を発見しました。 'Observable.concat(localUsers.first()、remoteUsers) .distinct(新しい関数func1 <ユーザー、整数>){ @Overrideパブリック整数コール(ユーザユーザ){ 戻りuser.getId()。 } } ' –

    関連する問題