2016-07-05 2 views
0

У меня есть следующий сценарий. Я получаю данные с сервера с помощью Retrofit2. Я хочу загрузить Collection<Account> из Account объектов, и для каждой из этих учетных записей для загрузки Collection<Project> из Project объектов. В конце я хочу получить Map<Account, Collection<Project>> accountsWithProjects.Трансформация 2 RxJava Наблюдает за 1 Карта

У меня есть следующие методы:

  1. Observable<Collection<Account>> requestAllAccounts()
  2. Observable<Collection<Project>> requestProjectsInfoForTempoAccount(Account accunt)

Вопрос: Можно ли сжать или создать как-то итерация этих двух реактивных потоков и собрать все элементы к карте?

Я также могу получить коллекцию проектов для учетной записи синхронно, если это помогает, однако не может сделать это на главной теме, так как разработка для Android и результат должен наблюдаться в основном потоке.

ответ

1

Вот лучший способ:

requestAllAccounts() 
.flatMap(account -> requestProjectsInfoForTempoAccount(account), 
    (acccount, projects) -> Pair::of) 
.toMap(Pair::key, Pair::value); 

(расширение на Java 7 осталось как excercise для читателя)

1

Там у вас есть:

requestAllAccounts().flatMap(new Func1<Collection<Account>, Observable<Account>>() { 
     @Override 
     public Observable<Account> call(Collection<Account> accountCollection) { 
      return Observable.from(accountCollection); 
     } 
    }).flatMap(new Func1<Account, Observable<Pair<Account, Collection<Project>>>>() { 
     @Override 
     public Observable<Pair<Account, Collection<Project>>> call(Account account) { 
      return Observable.just(account).zipWith(requestProjectsInfoForTempoAccount(account), 
        new Func2<Account, Collection<Project>, Pair<Account, Collection<Project>>>() { 
         @Override 
         public Pair<Account, Collection<Project>> call(Account account, Collection<Project> projects) { 
          return new Pair<Account, Collection<Project>>(account, projects); 
         } 
        }); 
     } 
    }).toList() 
      .flatMap(new Func1<List<Pair<Account, Collection<Project>>>, Observable<Map<Account, Collection<Project>>>>() { 
       @Override 
       public Observable<Map<Account, Collection<Project>>> call(List<Pair<Account, Collection<Project>>> pairs) { 
        Map<Account, Collection<Project>> map = new HashMap<Account, Collection<Project>>(); 
        for (Pair<Account, Collection<Project>> pair : pairs) { 
         map.put(pair.first, pair.second); 
        } 
        return Observable.just(map); 
       } 
      }); 

Что здесь происходит?

  1. Получить все счета.
  2. Split список на отдельные счета
  3. Invoke ищут проекты по одной учетной записи и вернуть Pair<Account, Collection<Project>>
  4. Объединить все объекты
  5. Transform List<Pair<Account, Collection<Project>>> в Map<Account, Collection<Project>>
+0

Спасибо, есть только одна проблема, которую я пытаюсь решить. Наблюдаемый вами объект испускает множество экземпляров 'Map >'. Каждый экземпляр имеет только один Map.Entry. Есть ли способ объединить их все на одной карте перед подпиской? –

+0

Вы уверены? Если функции 'requestAllAccounts()' и 'requestProjectsInfoForTempoAccount (Account accunt)' возвращают коллекции только один раз (один 'onNext (...)' call), он должен работать как ожидалось. –

+0

Да, извините, верно. Я попытался переписать его с помощью лямбда и что-то испортил. Еще раз спасибо! –

Смежные вопросы