2017-04-12 5 views
0

Ich möchte den/die nächsten Artikel laden, wenn ein anderes Observable einen neuen Gegenstand (einen Auslöser) auslöst.RxJava Artikel auf Anfrage laden

Dies ist der Code, der die Elemente emittiert: Ich konnte dieses Problem umgehen, war mit einem Subject und hält einen Verweis auf eine Liste von

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

Der einzige Weg:

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); 
      }); 
     } 
    }); 
} 

Trigger-Observable ids, die nicht elegant war und nicht reagierte.

Edit: Das ist meine Lösung bisher, aber ich musste abonnieren Ereignis direkt zu abonnieren. Ich halte das nicht für elegant.

@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

Verwenden Sie eine Flatmap für Ihre clickObservable. –

+0

@PhoenixWang Dies ist, was ich mit dem 'Subject' Ansatz mache, das Problem ist, wie man' n' Zählimpulse von 'idApi' erhält, wenn der Auslöser einen neuen Gegenstand aussendet. – Pedram

+0

Also laden Sie eine Liste von IDs aus API und möchten Daten für nächste ID laden, wenn auf eine Schaltfläche geklickt wird? oder willst du die ids nochmal mit den daten laden? – Lamorak

Antwort

2

Verwenden zip

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); 
      }); 
     } 
    }); 
} 

bekommen N Artikel mit jedem Klick

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); 
       }); 
       } 
     } 
     }); 
} 

Edit: Sie werden noch subscribeOn verwenden, um sicherzustellen, dass Sie auf dem Hauptthread für RxView .clicks und auf dem IO-Thread für jedes Netzwerk.

+0

Danke, das funktioniert tatsächlich, aber ich bekomme Fehler von 'RxBinding', weil es nicht auf' Hauptthread' ist, wenn ich es zum Hauptthread ändere, bekomme ich einen Fehler wegen 'Netzwerk am Hauptthread'. Ich musste 'subscribeOn (Schedulers.io())' vor Netzwerkaufrufen und 'subscribeOn (AndroidScheduler.mainThread())' nach zipWith hinzufügen. Gibt es eine andere Option? – Pedram

+0

Und was, wenn ich 'n' Elemente anstelle von einem mit jedem Auslöser laden möchte? – Pedram

+0

Ich habe herausgefunden, der Puffer kann dies tun, aber es erfordert eine andere Flatmap, die irgendwie redundant ist. Akzeptiere dies als Antwort, danke nochmal. – Pedram

1

Nicht so gut, aber es funktioniert:

Ihre get-Methode:

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); 
     }); 
    }) 
} 

Ihr Klick:

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

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

Ich mag würde diese Antwort mit zipwith() empfehlen, scheint besser als meine Antworten.

Verwandte Themen