如何使用rxjava处理多个数据源?

时间:2016-06-01 13:18:40

标签: rx-java retrofit2 rx-android sqlbrite

情况就是这样:

我有域层为业务逻辑提供数据获取接口,我有2个数据源:本地数据库和远程网络。

它的工作原理如下:

  1. 请求所有用户:DataRepository.getInstance().getUsers();
  2. 在DataRepository中,有两个来源:
    • LocalDataSource.getUsers()从本地数据库中提取所有用户,如果没有数据则忽略此请求。
    • RemoteDataSource.getUsers()从我们的服务器请求最新的用户列表(即使本地数据库中有数据,为了保持数据更新),当请求数据然后将其保存或更新到本地数据库并发送回结果。
  3. 我知道我可以通过DataRepository

    来实现我的目标
    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);
                }
            }
        });
    }
    

    现在认为我已经在项目中使用了rxjava,为什么不使用SqlBrite和Retrofit2 RxAdapters来实现这一目的更方便呢? 因此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); // ???
    }
    

1 个答案:

答案 0 :(得分:4)

  

我应该在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);
}

此外,如果您只想要一个结果(更快一个获胜),您可以使用amb

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