2016-03-21 16 views
4

RxJava ile bir Android uygulaması yapıyorum, sayfanın birinde, bir düğmeye bastığımda, basıldığında, sayfa yenilenecek. Ayrıca, kullanıcı o andaki düğmeye basmamışsa, her 10 saniyede bir otomatik yenilemeyi istiyorum. Ancak kullanıcı bu düğmeyi tıkladığında, otomatik yenileme eyleminin tıklamadan 10 saniye sonra gerçekleşmesini istiyorum. Kendi 10 saniyelik aralığına devam etmek yerine. Örneğin, ikinci 0'da, uygulama bir otomatik yenileme yapar, ardından ikinci 3'te kullanıcı düğmeye bastı. Daha sonra otomatik yenileme, ikinci 13, ikinci 23, vb. Olmalıdır. Belirli bir aralıkta öğeleri yayan bir interval() işleci olduğunu biliyorum. Ama başlangıç ​​zamanını sıfırlamak için bir yol yok gibi görünüyor. Bazı abonelikten çıkmak ve tekrar Gözlemlenebilir interval() abone olabilir. "Ayırmanızı" intervalObservable, o zaman onNext bunu birleştirmeyi iptal edebilir ve yeniden birleştirmek için bir yolu varsa bir kod parçasıdırrxjava interval() bazı olaylardan sonra sıfırlama süresi

Observable<Long> intervalObservable = Observable.inteval(10, TimeUnit.SECONDS) 
RxView.click(refreshButton).map(ignored -> 0L) 
     .merge(intervalObservable) 
     .subscibe(ignore -> performRefresh()); 

gibi olurdu. Ama öyle değil. Bunu nasıl başarabilirim?

cevap

11

Sen switchMap operatörü ile oldukça güzel yapabilirsiniz. Düğmeye her basıldığında anahtarını gözlemlenebilir aralığın yeni bir aboneliğine geçirir - yani tekrar başlayacaktır. Bir önceki abonelik otomatik olarak bırakılır, böylece birden fazla aralık çalışmayacaktır.

Observable<Long> intervalObservable = Observable.interval(10, TimeUnit.SECONDS); 

RxView.clicks(refreshButton) 
    .switchMap(ignored -> { 
     return intervalObservable 
      .startWith(0L)     // For an immediate refresh 
      .observeOn(AndroidSchedulers.mainThread()) 
      .doOnNext(x -> performRefresh()); 
    })  
    .subscribe(); 

startWith (düğmesi tıklandığında hemen yenileme neden olan) aralıkta hemen bir değer katar ve observeOn aralık bir arka plan üzerinde yayacaktır beri yenileme ana iş parçacığı üzerinde (önemli olur emin olur iplik).

Güncelleme: Vman kullanıcı düğmesine ilk kez tıkladıktan sonra bu uygulama yalnızca ferahlatıcı başladığını fark ettim. Aşağıdaki alternatif, aboneliğin ardından hemen yenilenecek, daha sonra her 10 saniyede bir düğmeye basılana kadar - bu noktada hemen yeniden yenilenecek, ardından her 10 saniyede bir güncellenmeye devam edecektir. Bu uygulama yenilenmesi yaptığı bir gözlenebilir olarak

Observable<Long> intervalObservable = Observable.interval(10, TimeUnit.SECONDS) 
    .startWith(0L) // For an immediate refresh 
    .observeOn(AndroidSchedulers.mainThread()) 
    .doOnNext(x -> performRefresh()); 

Observable<Long> buttonClickedObservable = RxView.clicks(refreshButton) 
    .map(e -> 0L) // To make the compiler happy 
    .switchMap(ignored -> Observable.error(new RuntimeException("button pressed"))); 

Observable.merge(intervalObservable, buttonClickedObservable) 
    .retry() 
    .subscribe(); 

hemen (ani bir yenileme yol açan ve her 10 saniyede tekrarlanan), O yenile düğmesine tıklandığında hata olacağı bir gözlemlenebilir ile birleşti oluyor abone olur. Sonunda retry, her şeyin bir hataya (düğme tıklatılarak) yeniden gönderilmesine neden olacak ve bu da yeniden baştan başlamasına neden olacaktır.

+1

Bu tam olarak istediğim şey! Teşekkür ederim! –

+0

@ patrick-bacon, OP'in sadece bir tıklama olmaması durumunda yazdığı birleştirme işlemine hala ihtiyaç duyuyorsunuz, böylece aralık hala 10 dak. – vman

+0

@vman - Düğmeye hiçbir zaman tıklanmamış olsa bile her 10 saniyede bir yenilenmesi gerektiğini anlamadım. Bu biraz daha karmaşık hale getirecek, ama yine de yapılabilir. Bunu destekleyen ikinci bir örneğim olması için cevabımı güncelleyip güncelleyemeyeceğimi göreceğim. İyi yakalama! –

2

En kolay çözüm, düğmeye her tıkladığınızda, eski gözlemlenebilir aboneliği iptal edip tekrar abone olabilir misiniz?

Subscription subscription= null; 
    Observable<Long> interval = nul; 


public void subscribe(){ 

    interval = Observable 
      .interval(10000L, TimeUnit.MILLISECONDS); 
    subscription = interval.subscribe(item -> System.out.println("doing something")); 

} 

public void eventClick(){ 
    if(clickButtin){ 
     subscription.unsubscribe(); 
     subscribe(); 
    } 
} 
+0

Bunu düşündüm, fakat bunu daha "akış" tarzında nasıl yapabilirim? Tıklama etkinliğinden bir Gözlemlenebilir hale getirdim ve bir 'aralıklı' gözlemlenebilir ile birleştirdim. Güncellenen soru açıklamasına bakın. –

+0

Eğer EvenClick başka bir gözlemlenebilir ise, bunu her zaman işlevsel bir şekilde yapabilirsiniz, eğer böyle bir yaklaşımla gitmezsem – paul