2015-02-09 2 views
0

У меня есть блок кода, который преобразует блок списка [VideoDetails] в VideoGrid используя заявления пары карт с ReactiveX:Transform Collection наблюдаемого в реакционно X Java

feedService.loadVideoDetailsFeed(things) 
      .map(new Func1<List<VideoDetails>, List<Video>>() { 
       @Override 
       public List<Video> call(List<VideoDetails> details) { 
        return Lists.transform(details, new Function<VideoDetails, Video>() { 
         @Override 
         public Video apply(VideoDetails input) { 
          return input.getVideo(); 
         } 
        }); 
       } 
      }) 
      .map(new Func1<List<Video>, VideoGrid>() { 
       @Override 
       public VideoGrid call(List<Video> videos) { 
        //stuff 
       } 
      }) 

Как вы можете видеть, I» m, используя преобразование Guava в одном из операторов отображения, чтобы перейти из списка [VideoDetails] в список [Видео]. Я бы предположил, что через ReactiveX есть лучший способ выполнить это преобразование? Я просматривал документы , но я мог бы быть слишком зеленым с ReactiveX, чтобы знать, что использовать здесь.

Вышеприведенный фрагмент кода работает, я бы скорее сделал это правильно, если это возможно.

ответ

1

Похоже, вам нужно сохранить буферизованный аспект потока VideoInfo для создания VideoGrid. Так что, если это так, то единственный способ остаться с Rx в целом - это сделать ненужным превращение этих подписок в наблюдаемые, а затем отобразить/трансформировать внутреннее наблюдаемое, только чтобы свернуть их обратно в списки при создании VideoGrid. То, как вы сейчас это делаете, вероятно, наиболее прагматично.

Если вам случится быть с помощью Java 8, вы можете угробить гуавы и внутренний класс:

return details.stream().map(VideoDetails::getVideo).collect(Collectors.toList()); 

Редактировать Вот способ сделать это пребывание в Rx

 feedService.loadVideoDetailsFeed(things) 
       .flatMap(new Func1<List<VideoDetails>, Observable<List<Video>>>() { 
        @Override 
        public Observable<List<Video>> call(final List<VideoDetails> videoDeets) { 
         return Observable.from(videoDeets).map(new Func1<VideoDetails, Video>() { 
          @Override 
          public Video call(final VideoDetails videoDetails) { 
           return videoDetails.getVideo(); 
          } 
         }).toList(); 
        } 
       }) 
       .map(new Func1<List<Video>, VideoGrid>() { 
        @Override 
        public VideoGrid call(List<Video> videos) { 
         return VideoGrid.fromListOfVideos(videos); 
        } 
       }); 

И вот способ, который будет генерировать меньше мусора. Фактический наблюдаемый запрос более читабельен, но это больше кода в целом.

private static Func1<VideoDetails, Video> _getVideo = new Func1<VideoDetails, Video>() { 
    @Override 
    public Video call(final VideoDetails videoDetails) { 
     return videoDetails.getVideo(); 
    } 
}; 
private static Func1<List<VideoDetails>, Observable<List<Video>>> _mapVideoDetailsToVideos = new Func1<List<VideoDetails>, Observable<List<Video>>>() { 
    @Override 
    public Observable<List<Video>> call(final List<VideoDetails> videoDeets) { 
     return Observable.from(videoDeets).map(_getVideo).toList(); 
    } 
}; 
private static Func1<List<Video>, VideoGrid> _buildVideoGridFromVideos = new Func1<List<Video>, VideoGrid>() { 
    @Override 
    public VideoGrid call(List<Video> videos) { 
     return VideoGrid.fromListOfVideos(videos); 
    } 
}; 

private static void yourFunction(final VideoDeetsSource feedService, String things) { 
    feedService.loadVideoDetailsFeed(things) 
       .flatMap(_mapVideoDetailsToVideos) 
       .map(_buildVideoGridFromVideos); 
} 
+0

Имеет смысл. Рад узнать, что я не пропустил ничего очевидного. В крупном масштабе вы думаете, что было бы более результативно делать это в (хотя и более тупым) способом, которым вы и krp описываете? – Zack

+1

Я добавил код, который покажет вам, как вы можете оставаться в Rx все время, но он будет генерировать больше мусора, чем использование Guava. Весь объект Observable.from(). Map(). ToList() создает много временных объектов. В любом случае, если вы идете с помощью метода all-Rx или остаетесь с List.transform(), вы должны кэшировать свою функцию селектора/трансформатора как статическое поле, чтобы убедиться, что анонимный внутренний класс не создается в каждой точке привязки. –

+0

Что касается производительности во время выполнения, вам нужно будет профилировать код в контексте вашей системы, чтобы получить осмысленный ответ на этот вопрос. –

2

Сохраняя стиль RX вы можете использовать приведенный ниже пример:

редактировать

feedService.loadVideoDetailsFeed(things) 
     .flatMap(new Func1<List<VideoDetails>, Observable<Video>>() { 
      @Override 
      public Observable<Video> call(List<VideoDetails> videoDetailsList) { 
       return Observable.from(videoDetailsList).map(new Func1<VideoDetails, Video>() { 
        @Override 
        public Video call(VideoDetails videoDetails) { 
         return videoDetails.getVideo(); 
        } 
       }); 
      } 
     }) 
     .toList(); 
+0

Тестирование этого не похоже на компиляцию. Кажется, что параметр 1 параметра Func1 должен соответствовать аргументу 1 метода вызова. Есть ли метод, аналогичный toList(), но который делает обратный? – Zack

+0

Я отредактировал свой ответ, чтобы избежать путаницы – krp

1

Что вы можете сделать:

  • Начиная с Observable<List<VideoDetails>> затем преобразовать его в Observable<VideoDetails>.
  • Преобразуйте этот Observable<VideoDetails> в Observable<Video>.
  • Последнее изменение сторонами: Observable<Video> по отношению к Observable<List<Video>>.

Это очень легко с RxJava (используя синтаксис Java8)

feedService.loadVideoDetailsFeed(things) // Observable<List<VideoDetails>> 
      .flapMap(Observable::from) // Observable<VideoDetails> 
      .map(details -> details.getVideo()) // Observable<Video> 
      .toList() // Observable<List<Video>> 
      .map(/* doYourStuff */) 
      .subscribe();