当RxJava遇上Retrofit
在項目開發過程中,我們或多或少的使用過很多網絡請求庫。基本點的就是原生的http請求框架,好比HttpClient以及HttpUrlConnection等,略懂android開發的估計無人不知android-async-http或者volley啥的,再往上走,你可能會接觸okhttp等。今天我們將來介紹一個新的http請求框架,隆重推薦Retrofit
Retrofit是何方神圣
retrofit是Square公司出品的,為android和java提供一個類型安全的Http網絡請求庫,這里是官網地址。
Retrofit的優點
使用注解來描述http請求
1.URL參數的替換和query參數的支持
2.對象轉化為請求體(如:JSON,protocol buffers等)
3.多重請求體和文件上傳
以上都是官網描述
使用流程
- 權限
這個沒什么好說的,沒有網絡權限什么都做不了
- 導包
這里幾個庫的含義是:我們使用retrofit2.0去進行網絡請求操作,同時我們使用gson去進行數據解析,并且結合rxjava去進行相應的代碼編寫
- 基本配置
這段就是使用RxJava,利用gson做解析(這邊解析器可以設置注入Jackson之類的,甚至可以自定義),http引擎框架是okhttp
- API說明
Retrofit需要通過注解請求方法以及請求參數來表明應該如何去進行一個Http請求,目前內置了5種注解方式GET、POST、PUT、DELETE以及HEAD。同時資源的相對URL要在注解中明確的指出。比如請求方法
@Get("/a/b")- api使用
配置都OK之后,現在就開始寫URL接口了。
案例1
假設有這么一個請求
看看這個GET請求,有header也有urlParam。我們可以使用@Header對header部分進行描述,后面使用@Query去添加每一個跟隨urlParam
@GET("weatherservice/cityname") Observable<WeatherModel> getWeatherModels(@Header("apikey") String apikey, @Query("cityname") String cityname);同時如果你覺得一個一個的@Query寫的有點煩,Retrofit支持使用@QueryMap,將請求的urlParam都存儲在一個Map里
案例2
假設有這么一個請求,來自gankio
看看這個GET請求,跟之前的區別在于,他沒有urlParam,但是參數是在url里面,這個時候我們就要采用動態替換url里面的參數的方法,如何做呢?用{}來表明url中的哪部分參數需要替換,相應的參數用@Path來注解同樣的字符串
@GET("{type}/{pagenum}/{page}") public Observable<GankioModel> getGankioModels(@Path("type") String type, @Path("pagenum") int pagenum, @Path("page") int page);案例3
假設有這么一個請求,
看看這個post請求,與之前的get請求基本類似,只不過請求參數在bodyparams里面了,這個也很簡單,通過@Body注解來指定一個方法作為HTTP請求主體
@POST("shipin_kg/shipin_kg") public Observable<MovieModel> getMovieLists(@Header("apikey") String apikey, @Body MoviePostModel postModel);案例4
我們在post請求的時候會遇到一種情況就是content-type被指定為某一種格式了
如果服務端告訴你,我們的請求一定要用x-www-form-urlencoded,那么之前說的那種@body就不起作用了,這個時候我們@FormUrlEncoded去表明這個content-type類型,同時要用@Field去處理每一個鍵值對
當然一個個寫@Field也很煩,可以直接用@FieldMap去統一用map來處理
案例5
上傳文件時候content-type一般都是multipart/form-data,所以這邊要加上 @Multipart 注解,同時每個請求部分需要使用 @Part 來注解。這邊用七牛上傳文件來說明
@Multipart @POST("http://upload.qiniu.com/") Call<ResponseBody> uploadImage(@PartMap Map<String, RequestBody> params);同樣使用了@PartMap
來看看RequestBody是怎么創建的
public static RequestBody create(final MediaType contentType, final File file) public static RequestBody create(MediaType contentType, String content) public static RequestBody create(final MediaType contentType, final byte[] content)找了3個基本方法,它是為了告訴我們,你可以通過contentType以及內容組成任意一個RequestBody對象
RequestBody body = RequestBody.create(MediaType.parse("image/jpeg"), new File(Environment.getExternalStorageDirectory().getPath() + "/PictureTest/saveTemp.jpg")); params.put("file", body); params.put("token", RequestBody.create(MediaType.parse("text/plain"), token)); params.put("x:jsonbody", RequestBody.create(MediaType.parse("text/plain"), "{}"));案例6
剛才看過了上傳,現在來看看下載。這邊只要借鑒了小凳子提供的下載方法
一般情況下retrofit是將整個文件都讀進內存里面的,這樣會造成OOM,所以大文件下載需使用@Streaming,同時我們也需要使用動態地址以便于下載不同的文件,這邊使用@Url來填充
剩下的就是保存文件了
Response<ResponseBody> response=api.downloadFileWithFixedUrl("http://7b1g8u.com1.z0.glb.clouddn.com/app_newkey_release_8_4.apk").execute(); try {if (response != null && response.isSuccessful()) {//文件總長度long fileSize = response.body().contentLength();long fileSizeDownloaded = 0;is = response.body().byteStream();File file = new File(Environment.getExternalStorageDirectory().getPath() + File.separator + "app_newkey_release_8_4.apk");if (file.exists()) {file.delete();} else {file.createNewFile();}fos = new FileOutputStream(file);int count = 0;byte[] buffer = new byte[1024];while ((count = is.read(buffer)) != -1) {fos.write(buffer, 0, count);fileSizeDownloaded += count;subscriber.onNext("file download: " + fileSizeDownloaded + " of " + fileSize);}fos.flush();subscriber.onCompleted();} else {subscriber.onError(new Exception("接口請求異常"));} } catch (Exception e) {subscriber.onError(e); } finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}} }具體使用
無論你是何種請求方式,在app上面調用的方式基本上都是差不多的,我就拿第一個天氣預報的接口加以說明
WeatherApi api = Retrofit2Utils.getInstance(getApplicationContext()).enableCache(true).getRetrofit("http://apis.baidu.com/apistore/").create(WeatherApi.class); subscription = api.getWeatherModels("a7802d983b3d58ed6e70ed71bb0c7f14", "南京").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).unsubscribeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<WeatherModel>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(WeatherModel weatherModel) {if (!subscription.isUnsubscribed()) {Log.d("MainActivity", (weatherModel.getRetData().getCity() + " " + weatherModel.getRetData().getDate() + "-" + weatherModel.getRetData().getTime() + " " + weatherModel.getRetData().getWeather()));}}});我這里使用了緩存操作,這個后面會加以說明。同時使用了Rxjava對請求的線程切換以及對返回結果進行調度
緩存
可以通過這篇文章Retrofit 源碼解讀之離線緩存策略的實現學習到Retrofit緩存的一些知識,真正實踐時我是在這里發現如何使用的Github
public class CacheInterceptor implements Interceptor {@Overridepublic Response intercept(Interceptor.Chain chain) throws IOException {Request request = chain.request();//如果沒有網絡,則啟用 FORCE_CACHEif(!isNetworkConnected()) {request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();}Response originalResponse = chain.proceed(request);if(isNetworkConnected()) {//有網的時候讀接口上的@Headers里的配置String cacheControl = request.cacheControl().toString();return originalResponse.newBuilder().header("Cache-Control", cacheControl).removeHeader("Pragma").build();} else {return originalResponse.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=3600").removeHeader("Pragma").build();}}public static boolean isNetworkConnected() {Context context = Retrofit2Utils.context;if (context != null) {ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();if (mNetworkInfo != null) {return mNetworkInfo.isAvailable();}}return false;} }本篇博文上的代碼已經共享到Github上,歡迎大家多多提意見
參考文章
- Retrofit 源碼解讀之離線緩存策略的實現
- 【譯】Retrofit 2 - 如何從服務器下載文件
- RxJava+Retrofit Samples解析
- Retrofit 2 + OkHttp 3 實現圖片上傳 (RxJava的方式)
- Retrofit筆記
- 使用Retrofit和Okhttp實現網絡緩存。無網讀緩存,有網根據過期時間重新請求
- Android Retrofit 2.0使用
總結
以上是生活随笔為你收集整理的当RxJava遇上Retrofit的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国产系统中标麒麟neokylin上的可视
- 下一篇: SQL Server AlwaysOn