2016-10-20 4 views
0

Мне нужно создать наблюдаемый, объединив несколько API-интерфейсов для переоснащения API.RxJava + Retrofit 2 запроса API цепочки

У меня есть 2 услуги: ItemService, который содержит только имя элемента и идентификатор, и ItemDetailsService, который содержит много других подробностей о вещах, как описание изображения и т.д. Я использую Дооснащение 2 + RxJava + Dagger 2.

ItemService :

@GET("apione/items") 
Observable<List<Items>> getItems(); 

ItemDetailsService:

@GET("apitwo/item/{id}") 
Observable<ItemDetail> getItemDetails(@Path("id") int id); 

товары JSON:

[ 
    { 
    "id": 1, 
    "name": "one" 
    }, 
    { 
    "id": 2, 
    "name": "two" 
    }, 
    { 
    "id": 3, 
    "name": "three" 
    } 
] 

ItemDetails JSON для Item ID для бетона:

{ 
    "id": 1, 
    "image_url": "http://.../1.png", 
    "description": "description of item one", 
    "category": "cat_1", 
    "quantity" 10 
    } 

Кроме того, эти 2 API, имеют различный базовый URL. Итак, как можно сделать Observable, который возвращает список предметов с их изображением, количеством и категорией?

ОБНОВЛЕНО

Я stucked здесь. Это мой ItemPresenter

public class ItemPresenter extends BasePresenter<ItemView> implements Observer<List<Item>> { 

    @Inject protected ItemService mItemService; 

    @Inject protected ItemDetailsService mItemDetailsService; 

    @Inject 
    public ItemPresenter() { 

    } 

    public void getItems() { 
     getView().onShowDialog("Loading"); 
     Observable<List<Item>> itemObservables= mItemService.getItems() 
       .flatMap(new Func1<List<Item>, Observable<ItemDetail>>() { 
        @Override 
        public Observable<ItemDetail> call(List<Item> items) { 
         List<Observable<ItemDetail>> detailObservables = new ArrayList<>(); 
         for (Item item : items) { 
          detailObservables.add(mItemDetailsService.getItemDetail(item.getId()); 
         } 
         return Observable.zip(
           detailObservables, 
           args -> { 
            List<Item> itemDetails = new ArrayList<>(); 
            for (Object arg : args) { 
             itemDetails.add((Item) arg); 
            } 
            return itemDetails; 
           } 
         ); 
        } 

       }); 

     subscribe(detailObservables, this); 
    } 

    @Override 
    public void onCompleted() { 
     getView().onHideDialog(); 
     getView().onShowToast("Complete"); 
    } 

    @Override 
    public void onError(Throwable e) { 
     getView().onHideDialog(); 
     getView().onShowToast("Error loading " + e.getMessage()); 
    } 

    @Override 
    public void onNext(List<Item> items) { 
     getView().onItems(items); 
    } 

} 

Dont понять, как сделать это правильно. И что мне нужно сделать, если мне нужно лишь немного подробностей о элементах в списке, а не о деталях из ItemDetail?

Мне нужно только добавить некоторые детали из ItemDetail в список Items.

+0

Мм ... 'FlatMap'? – EpicPandaForce

+0

Простите, но можете ли вы привести пример? – STK90

ответ

0

Если я вас правильно понял, то это должно дать вам то, что вам нужно:

private Observable<List<ItemDetail>> getItemDetails() { 
    return service1.getItems() 
      .flatMap(new Func1<List<Item>, Observable<List<ItemDetail>>>() { 
       @Override 
       public Observable<List<ItemDetail>> call(List<Item> items) { 
        List<Observable<ItemDetail>> detailObservables = new ArrayList<>(); 
        for (Item item : items) { 
         detailObservables.add(service2.getItemDetails(item.id)); 
        } 
        return Observable.zip(
          detailObservables, 
          new FuncN<List<ItemDetail>>() { 
           @Override 
           public List<ItemDetail> call(Object... args) { 
            List<ItemDetail> itemDetails = new ArrayList<>(); 
            for (Object arg : args) { 
             itemDetails.add((ItemDetail) arg); 
            } 
            return itemDetails; 
           } 
          } 
        ); 
       } 
      }); 
} 

Обратите внимание, что я предполагал, в этом коде, что ваш метод getItemDetails возвращает список ItemDetail объектов, просто для ясности коды ,

Объяснение: Я использовал оператор flatMap() обрабатывать список элементов, полученным от первого запроса службы, затем Наблюдаемый создаются для каждого запроса пункта подробно API и добавлен к списку detailObservables. Затем используется оператор zip, который в основном запускает все запросы и запускает обратный вызов в FuncN, когда все запросы завершены. Вы должны наложить Object на ItemDetail.

Редактировать: Я добавил service1 и service2 перед именами методов, чтобы сделать его более понятным, что я имел в виду.

+0

getItemDetails возвращает объект, и это две разные службы. – STK90

+0

Возможно, мой вопрос был неправильным, я отредактировал мое сообщение. – STK90

+0

Я добавил небольшое объяснение в конце ответа, которое может подтолкнуть вас в правильном направлении. – ehehhh

0
getItems().flatMap(
    // ... 
    return Observable.from(list); 
    // ... 
).flatMap(
    // ... 
    getItemDetails(id) 
    // ... 
).toList(); 
1

Для достижения вашей цели, вы должны следовать следующему алгоритму:

  1. запроса списку элементов с сервера.Теперь ваши наблюдаемые испускают List<Item>;
  2. Излучение от List<Item> для испускания только Item;
  3. Для каждого экземпляра Item необходимо скачать экземпляр ItemDetail. Как mItemDetailsService.getItemDetails(@Path("id") int id) возвращение Observable<ItemDetail>, поэтому для этого вам необходимо использовать flatMap(...);
  4. Объединение элементов ItemDetail в списке.

Код:

Observable<List<ItemDetail>> detailObservables = mItemService.getItems() 
    .flatMap(new Func1<List<Item>, Observable<Item>>() { 
    @Override 
     public Observable<Item> call(List<Item> items) { 
     return Observable.from(items); 
     } 
    }) 
    .flatMap(new Func1<Item, Observable<ItemDetail>>() { 
     @Override 
      public Observable<ItemDetail> call(Item item) { 
      return mItemDetailsService.getItemDetail(item.getId()); 
      } 
     }).toList(); 

Если вам нужно, например, просто IMAGE_URL вместо всей детали элемента, можно назвать:

.map(new Func1<ItemDetail, String>() { 
    @Override 
     public String call(Object itemDetail) { 
      return itemDetail.getImageUrl(); 
     } 
    }) 
Смежные вопросы