2017-04-12 52 views
0

我想在某些其他observable發出新項目(觸發器)時加載下一個項目。RxJava按需加載項目

這是發出的物品代碼:

public Observable<Item> get() { 
    return idApi.get().flatMap(new Function<List<String>, ObservableSource<String>>() { 
     @Override 
     public ObservableSource<String> apply(@NonNull List<String> ids) throws Exception { 
      return Observable.fromIterable(ids); 
     } 
    }).flatMap(new Function<String, ObservableSource<Item>>() { 
     @Override 
     public ObservableSource<Item> apply(@NonNull final String id) throws Exception { 
      return dataApi.get(id).map(new Function<Data, Item>() { 
       @Override 
       public Item apply(@NonNull Data data) throws Exception { 
        return new Item(data , id); 
      }); 
     } 
    }); 
} 

觸發可觀察:使用Subject並保持到列表的引用

RxView.clicks(view.findViewById(R.id.button_more)).debounce(500, TimeUnit.MILLISECONDS); 

我能解決這個問題的唯一辦法是這不是優雅而且看起來沒有反應的ID。

編輯:這是我的解決方案,但我不得不直接訂閱觸發事件。我不認爲它優雅。

@Override 
public Observable<Item> get(final Observable<Object> trigger) { 
    final PublishSubject<Item> subject = PublishSubject.create(); 
    return idApi.get().flatMap(new Function<List<String>, ObservableSource<Queue<String>>>() { 
     @Override 
     public ObservableSource<Queue<String>> apply(@NonNull List<String> ids) throws Exception { 
      final Queue<String> q = new LinkedList<>(ids); 
      return Observable.just(q); 
     } 
    }).flatMap(new Function<Queue<String>, ObservableSource<Item>>() { 
     @Override 
     public ObservableSource<Item> apply(@NonNull final Queue<String> ids) throws Exception { 
      trigger.subscribeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Object>() { 
       @Override 
       public void accept(@NonNull Object o) throws Exception { 
        if (ids.size() > 0) { 
         final String id = ids.poll(); 
         dataApi.get(id).map(new Function<Data, Item>() { 
          @Override 
          public Item apply(@NonNull Data data) throws Exception { 
           return new Item(data, id) l 
          } 
         }).subscribe(new Consumer<Item>() { 
          @Override 
          public void accept(@NonNull Item item) throws Exception { 
           subject.onNext(item); 
          } 
         }); 
        } else { 
         subject.onComplete(); 

        } 
       } 
      }); 
      return subject; 
     } 
    }); 
} 
+0

爲您的clickObservable使用平面地圖。 –

+0

@PhoenixWang這就是我用'Subject'方法做的事情,問題是每當觸發器發出一個新項目時如何從'idApi'獲得'n'個發射計數。 – Pedram

+0

所以你加載一個API列表,你想加載數據的下一個ID時點擊一個按鈕?或者你想用數據再次加載ID? – Lamorak

回答

2

使用拉鍊

public Observable<Item> get(View v) { 
    return idApi.get().flatMap(new Function<List<String>, ObservableSource<String>>() { 
     @Override 
     public ObservableSource<String> apply(@NonNull List<String> ids) throws Exception { 
      return Observable.fromIterable(ids); 
     } 
    }).zipWith(RxView.clicks(v).debounce(500, TimeUnit.MILLISECONDS), (n, i) -> n))  
    .flatMap(new Function<String, ObservableSource<Item>>() { 
     @Override 
     public ObservableSource<Item> apply(@NonNull final String id) throws Exception { 
      return dataApi.get(id).map(new Function<Data, Item>() { 
       @Override 
       public Item apply(@NonNull Data data) throws Exception { 
        return new Item(data , id); 
      }); 
     } 
    }); 
} 

得到N個項目,每個點擊

public Observable<Item> getN(View v, int nitems) { 
    return idApi.get().flatMap(new Function<List<String>, ObservableSource<String>>() { 
      @Override 
      public ObservableSource<String> apply(@NonNull List<String> ids) throws Exception { 
       return Observable.fromIterable(ids); 
      } 
     }).buffer(nitems).zipWith(RxView.clicks(v).debounce(500, TimeUnit.MILLISECONDS), (n, i) -> n)) 
     .flatMap(new Function<List<String>, ObservableSource<String>>() { 
      @Override 
      public ObservableSource<String> apply(@NonNull final List<String> ids) throws Exception { 
       return Observable.from(ids) 
      } 
     } 
     ) 
     .flatMap(new Function<String, ObservableSource<Item>>() { 
      @Override 
      public ObservableSource<Item> apply(@NonNull final String id) throws Exception { 
       return dataApi.get(id).map(new Function<Data, Item>() { 
        @Override 
        public Item apply(@NonNull Data data) throws Exception { 
         return new Item(data , id); 
       }); 
       } 
     } 
     }); 
} 

編輯:您仍然將不得不使用subscribeOn,以確保你是RXView在主線程.clicks和任何網絡的IO線程。

+0

謝謝,這實際上有效,但是我從'RxBinding'得到錯誤,因爲它不在'主線程'上,如果我將它改爲主線程,由於'主線程上的網絡',我得到錯誤。我必須在zipWith之後的網絡調用和subscribeOn(AndroidScheduler.mainThread())之前添加'subscribeOn(Schedulers.io())'。 還有其他的選擇嗎? – Pedram

+0

如果我想在每個觸發器中加載'n'項而不是一個項? – Pedram

+0

我想出緩衝區可以做到這一點,但它需要另一個平面圖,這是有點多餘的。接受這個答案再次感謝。 – Pedram

1

不太好,但它的工作原理:

您get方法:

Observable<Item> get(final String id){ 
    return Observable.defer(() -> { 
    dataApi.get(id).map(new Function<Data, Item>() { 
      @Override 
      public Item apply(@NonNull Data data) throws Exception { 
       return new Item(data , id); 
     }); 
    }) 
} 

您點擊:

private List<String> ids = {//your id s} 
private int current = 0; 

RxView.clicks(view).flatmap(ignore -> get(ids.get(current++))) 
        .subscribe(//your Observer) 

我想建議的答案與zipwith(),似乎比我好回答。