通過(guò)使用Retrofit+RxJava和Volley獲取知乎日?qǐng)?bào)消息,比較兩者的使用區(qū)別。
run.gif
文中 RR:代指Retrofit+Rxjava
主要兩個(gè)方面使用
- 使用兩者獲取Json數(shù)據(jù),使用Gson解析。
- 使用兩者獲取網(wǎng)絡(luò)圖片
1.第一步添加RR和Volley的gradle依賴(lài)
//google's volley
compile 'com.mcxiaoke.volley:library:1.0.19'
//RxAndroid
compile 'io.reactivex:rxandroid:1.2.1'
//RxJava
compile 'io.reactivex:rxjava:1.2.3'
//Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
2.分析知乎首頁(yè)Api返回的Json格式
Json.png
分析圖片來(lái)自GitHub [izzyleung](https://github.com/izzyleung)/**[ZhihuDailyPurify](https://github.com/izzyleung/ZhihuDailyPurify)**
3.構(gòu)建bean
在AndroidStudio里我是使用一個(gè)Json2Pojo插件,可以直接將Json對(duì)象轉(zhuǎn)換為適合Gson的JavaBean
Json2Pojo
在AS的插件管理里可以直接安裝 Json2Pojo
/**
* 知乎當(dāng)日消息
*/
public class Stories {
//供 Google Analytics 使用
@SerializedName("ga_prefix")
private String mGaPrefix;
//url 與 share_url 中最后的數(shù)字(應(yīng)為內(nèi)容的 id)
@SerializedName("id")
private Long mId;
//圖像地址(官方 API 使用數(shù)組形式。目前暫未有使用多張圖片的情形出現(xiàn),曾見(jiàn)無(wú) images 屬性的情況,請(qǐng)?jiān)谑褂弥凶⒁?)
@SerializedName("images")
private List<String> mImages;
//消息是否包含多張圖片(僅出現(xiàn)在包含多圖的新聞中)
@SerializedName("multipic")
private Boolean mMultipic;
//消息標(biāo)題
@SerializedName("title")
private String mTitle;
//作用未知
@SerializedName("type")
private Long mType;
public Stories(String mGaPrefix, Long mId, List<String> mImages, Boolean mMultipic, String mTitle, Long mType) {
this.mGaPrefix = mGaPrefix;
this.mId = mId;
this.mImages = mImages;
this.mMultipic = mMultipic;
this.mTitle = mTitle;
this.mType = mType;
}
public void setGaPrefix(String mGaPrefix) {
this.mGaPrefix = mGaPrefix;
}
public void setId(Long mId) {
this.mId = mId;
}
public void setImages(List<String> mImages) {
this.mImages = mImages;
}
public void setMultipic(Boolean mMultipic) {
this.mMultipic = mMultipic;
}
public void setTitle(String mTitle) {
this.mTitle = mTitle;
}
public void setType(Long mType) {
this.mType = mType;
}
public String getGaPrefix() {
return mGaPrefix;
}
public Long getId() {
return mId;
}
public List<String> getImages() {
return mImages;
}
public Boolean getMultipic() {
return mMultipic;
}
public String getTitle() {
return mTitle;
}
public Long getType() {
return mType;
}
@Override
public String toString() {
return "Stories{" +
"mGaPrefix='" + mGaPrefix + '\'' +
", mId=" + mId +
", mImages=" + mImages +
", mMultipic=" + mMultipic +
", mTitle='" + mTitle + '\'' +
", mType=" + mType +
'}';
}
}
4.定義Retrofit和Volley的單例管理
獲取Retrofit單例
public class RetrofitManager {
static final String BASE_URL = "http://news-at.zhihu.com/api/4/news/";
private Retrofit retrofit;
private static RetrofitManager ourInstance = new RetrofitManager();
public static RetrofitManager getInstance() {
return ourInstance;
}
private RetrofitManager() {
}
/**
* 獲取retrofit單例
*
* @return Retrofit single
*/
public Retrofit getRetrofit() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
獲取Volley RequestQueue單例
public class VolleyManager {
private RequestQueue requestQueue;
private static VolleyManager ourInstance = new VolleyManager();
public static VolleyManager getInstance() {
return ourInstance;
}
private VolleyManager() {
}
/**
* 獲取 volley requestQueue 單例
*
* @param context activity
* @return volley requestQueue
*/
public RequestQueue getRequestQueue(Context context) {
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(context);
}
return requestQueue;
}
}
5.定義Retrofit REST Api 接口
//獲取Json數(shù)據(jù)
public interface GetNews {
@GET("latest")
Observable<Result> getNews();
}
//獲取圖片
public interface GetBitmap {
@GET
Observable<ResponseBody> getPicFromNet(@Url String url);
}
這里使用RxJava形式的接口定義,直接返回 被觀察者對(duì)象
6.獲取Json數(shù)據(jù),并返回Result對(duì)象
通過(guò)RR獲取
//get data by Retrofit & RxJava
private void getDataByRetrofit() {
progressBar.setVisibility(View.VISIBLE);
storiesAdapter.setGetPicByRR(true);// tell adapter get pic by retrofit
//RR:Retrofit+RxJava
Subscriber<Result> subscriber = new Subscriber<Result>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
public void onStart() {
super.onStart();
storiesList.clear();
}
//設(shè)置數(shù)據(jù)到RecyclerView
@Override
public void onNext(Result result) {
storiesList.addAll(result.getStories());
storiesAdapter.notifyDataSetChanged();
progressBar.setVisibility(View.INVISIBLE);
}
};
//主要邏輯
GetNews getNews = RetrofitManager.getInstance().getRetrofit().create(GetNews.class);
getNews.getNews()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(subscriber);
}
通過(guò)Volley獲取
/**
* get data by volley
*/
private void getDataByVolley() {
progressBar.setVisibility(View.VISIBLE);
storiesAdapter.setGetPicByRR(false);// tell adapter get pic by volley
//主要邏輯
StringRequest stringRequest = new StringRequest(Request.Method.GET,
RetrofitManager.BASE_URL + "latest",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
//Json to Bean
Gson gson = new Gson();
Result result = gson.fromJson(response, Result.class);
storiesList.addAll(result.getStories());
//設(shè)置數(shù)據(jù)到RecyclerView
storiesAdapter.notifyDataSetChanged();
progressBar.setVisibility(View.INVISIBLE);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(context, error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
VolleyManager.getInstance().getRequestQueue(this.getApplication()).add(stringRequest);
}
7.Adapter中獲取圖片
通過(guò)RR獲取
//get pic by Retrofit and RxJava
Action1<Bitmap> bitmapAction1 = new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {
holder.ivImg.setImageBitmap(bitmap);
}
};
String url = stories.getImages().get(0);
GetBitmap getBitmap = RetrofitManager.getInstance().getRetrofit().create(GetBitmap.class);
getBitmap.getPicFromNet(url)
.map(new Func1<ResponseBody, Bitmap>() {
@Override
public Bitmap call(ResponseBody responseBody) {
//decode pic
return BitmapFactory.decodeStream(responseBody.byteStream());
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmapAction1);
通過(guò)Volley獲取
//get pic by volley
ImageLoader imageLoader = new ImageLoader(VolleyManager.getInstance()
.getRequestQueue(context.getApplicationContext())
, new ImageLoader.ImageCache() {
@Override
public Bitmap getBitmap(String url) {
return null;
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
}
});
ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(holder.ivImg, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
String url = stories.getImages().get(0);
imageLoader.get(url, imageListener);
Project目錄.png
8.總結(jié)
這里只是從簡(jiǎn)單的使用層面上對(duì)比了RR和Volley兩者使用上的不同,之前獲取網(wǎng)絡(luò)數(shù)據(jù)的任務(wù)都是交給Volley來(lái)做。
有時(shí)獲取了A數(shù)據(jù)之后,馬上需要進(jìn)行下一步包裝分析A之后獲取B數(shù)據(jù)。
如果是在Volley中就會(huì)出現(xiàn)嵌套的邏輯;在RxJava中使用Retrofit就可以使用它的map(或flatMap)進(jìn)行A數(shù)據(jù)的包裝分析,之后返回B數(shù)據(jù)的,就不會(huì)出現(xiàn)嵌套的邏輯。
以上只是小生簡(jiǎn)單的對(duì)比,用以自身理解RxJava,有什么不對(duì)的地方歡迎各位指出 _