How to handle multiple data sources with rxjava?

社会主义新天地 提交于 2021-02-08 03:46:53

问题


This is the case:

I have the domain layer to provide data fetching interface for business logics, and I have 2 data sources: local database and remote network.

It works like this:

  1. Request all users: DataRepository.getInstance().getUsers();
  2. In DataRepository, there are 2 sources:
    • LocalDataSource.getUsers() which fetches all users from local database, if there is no data then ignore this request.
    • RemoteDataSource.getUsers() which requests latest user list from our server(Even if there is data in local database, for the purpose of keeping data updated), when data requested then save or update it to local database and send back the results.

I know that I may achieve my goal by doing this in 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);
            }
        }
    });
}

Now thinking that I already used rxjava in the project, why not using SqlBrite and Retrofit2 RxAdapters to do this for more convenience? So LocalDataSource.getUsers() now returns Observable<List<User>> and so does 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();
}

Question:

What should I do in DataRepository.getUsers() to achieve the same thing I did with the old tricks?

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:


What should I do in DataRepository.getUsers() to achieve the same thing I did with the old tricks?

In such case, you can use concat:

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

But if it doesn't matter whether local or remote result comes first, you can use merge:

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

In addition, if you only just want one result (quicker one wins), you can use amb:

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


来源:https://stackoverflow.com/questions/37569906/how-to-handle-multiple-data-sources-with-rxjava

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!