map:解决请求过程中,数据变换的操作,比如:请求到的结果是1、3、5,而我要的是2、6、10,很显然就是要结果的双倍,所以用map操作符处理一下,让他返回value*2。
flatmap:解决嵌套网络请求,比如:我先要请求拿到所有的学生的学号,然后再根据每个学号去请求拿到每个学生对应的姓名。你还可以再复杂一点,再根据每个学生的姓名中的姓,再去请求拿到所有这个姓氏的学生的List。
咱再举两个例子:
1、接口请求拿到所有城市,然后再根据拿到的城市的编码再去请求接口拿到每个城市的温度。
2、接口请求判断这个账号是否已注册,若已注册再去请求判断密码是否正确。
当然,这些东西后台全都可以搞定归结成一个接口给你,但是后台人员比较固执的话……我们前端也是可以搞的。
根据酷狗的搜索接口:http://mobilecdn.kugou.com/api/v3/search/song?format=json&keyword=歌名&page=1&pagesize=20 搜得歌曲列表,然后根据每个歌曲的hash值再去接口:http://m.kugou.com/app/i/getSongInfo.php?cmd=playInfo&hash=上面搜索的歌曲的hash值 中请求拿到歌曲的详情(包括专辑图链接和歌曲播放链接)。
public interface ApiService {
/**
* 酷狗搜索接口
*/
@GET("http://mobilecdn.kugou.com/api/v3/search/song?format=json")
Observable searchKugou(@QueryMap Map map);
/**
* 酷狗音乐详情
* @param hash 歌曲的hash
* @return 详情
*/
@FormUrlEncoded
@POST("app/i/getSongInfo.php?cmd=playInfo")
Observable getDetail(@Field("hash") String hash);
}
搜索接口给了全路径,那详情接口的域名“http://m.kugou.com/”就配置到baseUrl里面了。
至于这两个实体类太长了,我简单说一下:
KugouSearch:里面包含了我们歌曲列表,然后歌曲列表的每一项里面有一个我们想要的hash值,类似这项的id吧。
KugouDetail:里面包含专辑图链接和歌曲播放链接,这些是我们想要的详情,是搜索的结果里面没有的。
具体看文章末给的demo链接,就不列出来了。
Map map = new HashMap<>();
map.put("keyword",name);
map.put("page",page);
map.put("pagesize", BaseConstant.PAGE_SIZE);
Api.getApiService().searchKugou(map)
//搜索请求的结果,把他的歌曲列表拿出来遍历
.flatMap(new Function>() {
@Override
public Observable apply(KugouSearch kugouSearch) throws Exception {
//kugouSearch.getData().getInfo()是List类型,就是搜索出来的全部歌曲的列表
return Observable.fromIterable(kugouSearch.getData().getInfo());
}
})
//根据上面遍历的每一个歌曲,拿它的hash值
.flatMap(new Function>() {
@Override
public ObservableSource apply(KugouSearch.DataBean.InfoBean infoBean) throws Exception {
//获取歌曲详情的请求,传hash给第二个接口,拿到详情
return Api.getApiService().getDetail(infoBean.getHash());
}
})
//因为获取详情的接口只是获取一首歌的,我们要的是搜索到的所有歌曲的每首歌的详情
//toList可以转化成List
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(List value) {
//这样就拿到了我们想要的二次请求的数据了
getV().showData(value);
}
@Override
public void onError(Throwable e) {
getV().onError(e);
}
});