Gradle的配置(該配置是針對rxjava1.x的)
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4' //okhttp log 工具 compile 'com.squareup.okhttp3:logging-interceptor:3.1.2' compile 'com.google.code.gson:gson:2.5' compile 'io.reactivex:rxandroid:1.1.0' compile 'io.reactivex:rxjava:1.1.0' compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
##經常使用的註解php
@Path:該註解寫在方法中的參數類型(String)前面;用於指定@POST()或者@GET()請求中括號中的參數;該參數中不容許存在 斜槓 , 即只能表示一級,相似"目錄"; 能夠把全部的路徑都存在一個類中,在@Post()的括號中引用這個路徑,這樣@Path就不須要使用;除非相同路徑下都是最後一級不相同,可使用該註解。html
@ Url :該註解寫在方法的參數類型前面;表示完整的Url。java
@Query:用於自動拼接URL ?id=3&name=zhangsan&age=24;Post和Get請求中均可以使用react
@QueryMap :傳入一個Map類型,自動拼接URL;Post和Get請求中均可以使用android
@FormUrlEncoded 和Post一塊兒使用;提交沒有文件的表單數據;和參數註解@Field和@FieldMap配合使用git
@ Field:用於POST請求中,輸入拼接的請求體鍵值對;不帶文件上傳的表單提交github
@ FieldMap :用於POST請求中,輸入拼接的請求體鍵值對的Map對象;不帶文件上傳的表單提交json
@Streaming:下載文件必需要加上這個,保證下載的內容不會一會兒都加載到內存中去;表示和服務器是長鏈接,會邊下載流,邊處理(好比寫入存儲器中),使得內存不會有一直持有全部的流數據。api
@Multipart:提交帶有文件的表單使用;配合參數註解@Part和@PartMap使用;@PartMap的類型是 <String,RequestBody>服務器
@Part,@PartMap: 用於POST文件上傳 @PartMap接受的數據類型是HashMap<String,RequestBody> @Part用法:@Part("xxx") RequestBody body
@Body 若是上傳的內容不是用@MultiPart來修飾的,也不是要傳遞鍵值對。參數中不能用@Part或者@PartMap來修飾。此時選擇用@Body;好比傳遞一個json字符串給服務器,此時就須要body,還須要改一下Header
關於文件的上傳: 參見 :http://blog.csdn.net/zhangxing52077/article/details/52830045 文件的下載可使用 RxDownload
@Body:POST請求中的參數
@RequestBody
okhttp3.Media的常見type類型
eg: RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), jsonString);
text/html : HTML格式 text/plain :純文本格式
text/xml : XML格式 image/gif :gif圖片格式
image/jpeg :jpg圖片格式 image/png:png圖片格式 以application開頭的媒體格式類型:
application/xhtml+xml :XHTML格式 application/xml : XML數據格式 application/atom+xml :Atom XML聚合格式
application/json : JSON數據格式 application/pdf :pdf格式
application/msword : Word文檔格式 application/octet-stream : 二進制流數據(如常見的文件下載) application/x-www-form-urlencoded : <form encType=」」>中默認的encType,form表單數據被編碼爲key/value格式發送到服務器(表單默認的提交數據的格式)
另一種常見的媒體格式是上傳文件之時使用的: multipart/form-data : 須要在表單中進行文件上傳時,就須要使用該格式
@Headers :註解設置固定的請求頭,全部請求頭不會相互覆蓋,即便名字相同。
@Headers("Cache-Control: max-age=640000") @GET("widget/list") Call<List<Widget>> widgetList(); // 注意Headers括號中的鍵值對,冒號後面有一個空格!!!! @Headers({ "Accept: application/vnd.github.v3.full+json","User-Agent: Retrofit-Sample-App"}) @GET("users/{username}")Call<User> getUser(@Path("username") String username);
@Header 使用 @Header 註解動態更新請求頭,匹配的參數必須提供給 @Header ,若參數值爲 null ,這個頭會被省略,不然,會使用參數值的 toString 方法的返回值。
@GET("user") Call<User> getUser(@Header("Authorization") String authorization)
獲取Retrofit的實例
public class RetrofitClient { private static final String TAG = "RetrofitClient"; // private static final String BASE_URL ="https://api.douban.com/v2/movie/"; private static OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { // Log.v(TAG,chain.connection().route().address().toString()); Log.v(TAG,chain.request().url().toString()); Request.Builder builder = chain.request().newBuilder(); //添加共同的頭信息 // builder.addHeader("token", "abc"); return chain.proceed(builder.build()); } }) .connectTimeout(15, TimeUnit.SECONDS) .readTimeout(15, TimeUnit.SECONDS) .build(); private static class Holder{ private static Retrofit retrofit = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(StringConverterFactory.create()) .baseUrl(UrlConst.BASE_URL) .client(client) .build(); } public static Retrofit getRetrofitInstance() { return Holder.retrofit; } private static Retrofit retrofit2; public static Retrofit getStringRetrofitInstance(String url) { retrofit2 = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(StringConverterFactory.create()) .baseUrl(url) .client(client) .build(); return retrofit2; } public static Retrofit retrofit3; public static Retrofit getRetrofitInstance(String url) { retrofit3 = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(StringConverterFactory.create()) .baseUrl(url) .client(client) .build(); return retrofit3; } }
建立Service的接口
GET請求
//具體的網絡url : 舉例子:https://api.douban.com/v2/movie/top250?start=2&count=4 public interface ApiService { @GET("top250") Observable<Entity> getMovies(@Query("start") int start,@Query("count") int count); }
// 最好這麼寫,參數用變量代替 public interface ApiService { @GET("{url}") Observable<Entity> getMovies(@Path("url") String url, @Query("start") int start, @Query("count") int count); }
POST請求
public interface MovieService { //獲取豆瓣Top250 榜單 @FormUrlEncoded @POST("top250") Observable<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count); } 關於Post請求須要注意的幾個地方: 必需要有@FormUrlEncoded 配合 Filed使用時
下載文件的GET請求
//必需要加上@Streaming,否則會把下載的東西所有讀到內存中去 @Streaming @GET Observable<ResponseBody> downloadFile(@Url String url);
寫入ReponseBody到文件系統
/** * 將ResponseBody中的內容保存到本地路徑 ;該路徑必須已經存在 * * @param body * @param localPath */ public static void writeResponseBodyToDisk(ResponseBody body, String localPath) { File file = new File(localPath); InputStream is = null; OutputStream os = null; long totalLength = body.contentLength(); long currentLength = 0; double rate = 0; byte[] bytes = new byte[4096]; try { os = new FileOutputStream(file); is = body.byteStream(); int length = -1; while ((length = is.read(bytes)) != -1) { os.write(bytes, 0, length); currentLength += length; rate = currentLength * 1.0 / totalLength; } os.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (is != null) { is.close(); } if (os != null) { os.close(); } } catch (IOException e) { e.printStackTrace(); } } }
踩過的坑:
1.Post請求中
//獲取 任務 @POST("index.php/machine/{url}") Observable<String> getTask(@Path("url") String url, @Body RequestBody requestBody);
註解Post的括號中若是有引用方法的url時,那麼方法中的url不能包括斜槓 / ,也不能包括問號 ? 由於斜槓 / 會被轉義爲 %2F ; ? 會被轉義爲 %3F ;斜槓和問號只有寫在@POST的括號中才不會被轉義。
2.Post請求上傳多個文件和其餘字符串參數 文件上傳能夠用兩種方式來作: 1.使用MultipartBody.Part 類型修飾在函數的文件參數前面;文件的參數和字符串參數分開來作;字符串參數能夠用@PartMap來包裹
RequestBody apkBody = RequestBody.create(MediaType.parse("multipart/form-data"),file_apk); MultipartBody.Part partApk = MultipartBody.Part.createFormData("apk_url",file_apk.getName(),apkBody);
2.(用的少)使用@PartMap註解修飾參數類型前面 , 上傳多個文件,可是對建立文件的RequestBody作一步處理;這種方式實際上是把多個文件和字符串都放在@PartMap修飾的HasMap<String,RequestBody>中即:
RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"), file); RequestBody requestBody1 = RequestBody.create(MediaType.parse("multipart/form-data"), file1); Map<String, RequestBody> params = new HashMap<>(); params.put(key+"\"; filename=\""+ file.getName(), requestBody); params.put(key1+"\"; filename=\""+ file1.getName(), requestBody1);
3.若是服務器返回值不是一個json,而是一個字符串String。那麼咱們用的GsonConvertory的Retrofit就不可用了。須要自定義一個StringConvertory.
- 這種上傳方式沒有嘗試過:
MultipartBody.Part photo1part = MultipartBody.Part.createFormData("pic1", "pic2", requestBody1);
@Multipart @POST("upload.php") Observable<ResponseBody> uploadFile( @Part() List<MultipartBody.Part > files );
5.文件和參數同時上傳的時候會遇到參數的value若是是String,會有兩個雙引號在外面。緣由是因爲使用了 Map<String,String>的方式,可使用Map<String,RequestBody>的方式來解決這個問題。