2016-12-07 70 views
1

我试图让自己进入RxJava,所以我读了一些关于它的文章。我想我理解它是如何工作的,但我想向你提交一个理论代码,以确保我对图书馆有很好的理解。链接使用RxJava翻新电话

让我们想象一下,我有一个API可以检索产品列表,并为他们每个人他们生产的艺术家,他们的专辑和他们的歌曲。 我的模型将如下

public class Produceur { 
    private Integer id; 
    private String name; 
    private String pictureUrl; 
} 

public class Artist { 
    private Integer id; 
    private String name; 
    private String lastname; 
    private String sceneName; 
    private String pictureUrl; 
} 

public class Album { 
    private Integer id; 
    private int year; 
    private String name; 
    private String style; 
    private String pictureUrl; 
    private Integer artistId; 
} 

public class Song { 
    private Integer id; 
    private String title; 
    private int duration; 
    private String pictureUrl; 
    private Integer albumId; 
} 

与我Retrofist服务

@GET("myUrl/produceurs") 
Observable<List<ProduceurResponse>> getProduceurs(); 

@GET("myUrl/produceurs/{produceurId}") 
Observable<List<ArtisteResponse>> getArtistForProduceur(@Path("produceurId") Integer produceurId); 

@GET("myUrl/picture/{id}") 
Observable<ResponseBody> getPicture(@Path("id") Integer id); 

和响应对象

public class ProduceurResponse { 
    private Integer id; 
    private String name; 
    private String pictureUrl; 
} 

public class ArtisteResponse { 
    private Integer id; 
    private String name; 
    private String lastname; 
    private String sceneName; 
    private String pictureUrl; 
    private List<AlbumResponse> albums; 
} 

public class AlbumResponse { 
    private Integer id; 
    private int year; 
    private String name; 
    private String style; 
    private String pictureUrl; 
    private Integer artistId; 
    private List<SongResponse> songs; 
} 

public class SongResponse { 
    private Integer id; 
    private String title; 
    private int duration; 
    private String pictureUrl; 
    private Integer albumId; 
} 

我想检索所有produceur和每个艺术家和以相同的顺序将所有图像保存在本地存储器中。 我想到了下面的代码,每个产品我们都会检索艺术家,他们的专辑和歌曲,并将它们插入我们的基地。 一旦我们完成检索产品和艺术家,我们可以下载图像(我们存储在一个列表中每个id与图片)。

getProduceurs().flatMap(produceurs -> Observable.from(produceurs)) 
       .doOnNext(produceur -> insertProduceurInBase(produceur)) 
       .subscribe(produceur -> Observable.from(getArtistForProduceur(produceur.getId()) 
               .flatMap(artists -> Observable.from(artists)) 
               .doOnNext(artist -> insertArtistInBase(artist))) 
               .subscribe(), 

          e -> showError(e), 

         () -> Observable.from(listOfIdsToDownload) 
              .doOnNext(id -> getPicture(id)) 
              .subscribe(response -> createImage(response), 

              e -> showError(e), 

             () -> isFinished() 
             ) 
         ); 

这段代码能工作吗(我这么认为,但我不确定)?这是做这件事的最好方法吗?

现在,如果我的getProduceurs服务返回包含产品艺术家id的ProduceurResponse列表,并且我获得了检索艺术家配置文件的服务以及另一个检索其专辑的服务。

public class ProduceurResponse { 
    private Integer id; 
    private String name; 
    private String pictureUrl; 
    List<Integer> artistsIds; 
} 

public class ArtisteProfileResponse { 
    private Integer id; 
    private String name; 
    private String lastname; 
    private String sceneName; 
    private String pictureUrl; 
} 

@GET("myUrl/artist/{artistId}") 
Observable<List<ArtisteProfileResponse>> getArtistProfile(@Path("artistId") Integer artistId); 

@GET("myUrl/artist/{artistId}/detail") 
Observable<List<AlbumResponse>> getArtistAlbums(@Path("artistId") Integer artistId); 

我可以使用.ZIP使getArtistProfile()和getArtistAlbums()之类

getProduceurs().flatMap(produceurs -> Observable.from(produceurs)) 
       .doOnNext(produceur -> insertProduceurInBase(produceur)) 
       .subscribe(produceur -> Observable.from(produceur.getArtistIds()) 
               .zip(
                 getArtistProfile(), 
                 getArtistAlbums(), 
                 (artistProfil, albumList) -> insertArtistInBase() 
               ) 
               .subscribe(), 

          e -> showError(e), 

         () -> Observable.from(listOfIdsToDownload) 
              .doOnNext(id -> getPicture(id)) 
              .subscribe(response -> createImage(response), 

              e -> showError(e), 

             () -> isFinished() 
             ) 
         ); 

同时调用的东西,但我真的不知道我使用的是压缩的正确的方法。这段代码是否使用了zip?这会工作吗?这是做这件事的最好方法吗?

编辑

于是,我就实现类似我与谷歌图书API最初的想法的东西。

我已经有了一个更新接口

public interface IBookService { 
    @GET("volumes?q=robot+subject:fiction") 
    Observable<BookSearchResult> getFictionAuthors(@Query("category") String key); 
    @GET("volumes") 
    Observable<BookSearchResult> getBooksForAuthor(@Query("q") String author, @Query("category") String key); 
} 

随着

public class BookSearchResult { 
    public List<BookResult> items; 
} 

public class BookResult { 
    public String id; 
    public String selfLink; 
    public VolumeInfoResult volumeInfo; 
    public SaleInfoResult saleInfo; 
} 

我尝试用字符串机器人(getFictionAuthors)检索小说的书籍还给我包含一个BookSearchResult BookResult列表。对于每本书的结果,我都用getBooksForAuthor检索作者的所有书籍。我的代码是低于

Observable<BookResult> observable = mWebService.getFictionAuthors(API_KEY) 
       .flatMap(new Func1<BookSearchResult, Observable<BookResult>>() { 

        // Parse the result and build a CurrentWeather object. 
        @Override 
        public Observable<BookResult> call(final BookSearchResult data) { 
         return Observable.from(data.items); 
        } 
       }) 
       .concatMap(new Func1<BookResult, Observable<BookSearchResult>>() { 

        // Parse the result and build a CurrentWeather object. 
        @Override 
        public Observable<BookSearchResult> call(final BookResult data) { 
         return mWebService.getBooksForAuthor("=inauthor:" + data.volumeInfo.authors.get(0), API_KEY); 
        } 
       }) 
       .flatMapIterable(new Func1<BookSearchResult, List<BookResult>>() { 

        // Parse the result and build a CurrentWeather object. 
        @Override 
        public List<BookResult> call(final BookSearchResult data) { 
         return data.items; 
        } 
       }) 
       .subscribeOn(Schedulers.newThread()) 
       .observeOn(AndroidSchedulers.mainThread()) 
       .subscribe(new Subscriber<BookResult>() { 
        @Override 
        public void onNext(final BookResult book) { 
         Log.e("Book","Book is " + book.volumeInfo.title + " written by " + book.volumeInfo.authors.get(0)); 
        } 

        @Override 
        public void onCompleted() { 
         Log.e("Book","Book list completed"); 
        } 

        @Override 
        public void onError(final Throwable error) { 
         Log.e("Book","Book list error"); 
        } 
       } 

此代码工作,但有一些奇怪的,我不明白。在我的日志中,我首先从第一作者的getBooksForAuthor请求返回,然后从该作者的每本书中获得日志。之后,我得到了第二作者的请求以及他书中的部分日志的结果。按照其他作者请求的结果,然后查看第二作者的书籍列表的末尾以及所有其他作者的书籍列表。

来说明吧,我的日志看起来像

- > Return from request for Author 1 
- > Book 1 from author 1 
... 
- > Book 10 from author 1 
- > Return from request for Author 2 
- > Book 1 from author 2 
... 
- > Book 5 from author 2 
- > Return from request for Author 3 
- > Return from request for Author 4 
... 
- > Return from request for Author 10 
- > Book 6 from author 2 
.. 
- > Book 10 from author 2 
- > Book 1 from author 3 
.. 
- > Book 10 from author 3 
... 
- > Book 1 from author 10 
.. 
- > Book 10 from author 10 

当我预计

- > Return from request for Author 1 
- > Book 1 from author 1 
... 
- > Book 10 from author 1 
- > Return from request for Author 2 
- > Book 1 from author 2 
... 
- > Book 10 from author 2 
... 
- > Return from request for Author 10 
- > Book 1 from author 10 
... 
- > Book 10 from author 10 

是否有人有一个解释或理解我缺少的是什么?

+0

你想要什么,喜欢要保存在正确的序列中的图片? –

+0

我想检索我的所有数据并以相同的顺序保存我的图像。我记住的是,我登录,我的应用程序检索我需要的所有数据,然后我可以使用该应用程序。 – Tibo

+0

rxjava有这样的操作符:merge() - 它从api接收的顺序获取数据。 buffer():该运算符创建缓冲区,以便没有负载。你可以试试这个 –

回答

1

您应该避免嵌套订阅(检查flatmap运算符)。这是代码味道的一个指标。 为避免嵌套订阅,可以使用运算符flatMap(不要产生garanti产生的事件顺序)或concatMap(garanti产生的事件顺序)。

我也注意到您在完成的回调中使用了另一个Observable:在这种情况下,您可以使用concat观察值。

所以,你的代码的使用这种运营商的返工:

getProduceurs().flatMap(produceurs -> Observable.from(produceurs)) 
       .doOnNext(produceur -> insertProduceurInBase(produceur)) 
       // call getArtistForProduceur and emit results in order 
       .concatMap(produceur -> getArtistForProduceur(produceur.getId())) 
       // emits items of the list 
       .flatMapIterable(artists -> artists) 
       .doOnNext(artist -> insertArtistInBase(artist))) 
       // don't care about elements. But will wait for the completion of the previous observable 
       .ignoreElements() 
       // perform jobs after the previous observable complete 
       .concatWith(Observable.from(listOfIdsToDownload) 
             .doOnNext(id -> getPicture(id)) 
             .doOnNext(response -> createImage(response))) 
       // show an error if an error occur in the downstream 
       .doOnError(e -> showError(e)) 
       // call isFinished when everything is finished. 
       .doOnCompleted(() -> isFinished()) 
       .subscribe() 
+0

非常感谢,看起来好多了,我不知道concatMap。我仍然有一个问题:flatMapIterable(艺术家 - >艺术家)与flatMap(艺术家 - > Observable.from(艺术家))一样吗? – Tibo

+0

是的。请参阅:http://reactivex.io/RxJava/javadoc/rx/Observable.html#flatMapIterable(rx.functions.Func1) – dwursteisen

+0

感谢您的帮助! – Tibo