經過對Retrofit2.0的前兩篇的基礎入門和案例實踐,掌握了怎麼樣使用Retrofit訪問網絡,加入自定義header頭,包括加入SSL證書,基本的調試基礎,cookie同步問題,但不少場景需求是須要文件的上傳的,今天主題就來分享怎麼用Retrofit2.0+ RxJava 上傳文件和圖片,表單,包括上傳Json等。其實有無rxjava,Retrofit的圖片上傳姿式都同樣,api返回的call
換成 Observable
便可java
你們都知道在2.0之前版本上傳圖片的姿式git
public interface ApiManager { @Multipart @POST("/user/addCarInfo") void addCarInfo(@QueryMap Map<String, Object> options, @Part("file") TypedFile file, Callback<JsonElement> response); }
使用2.0,咱們發現之前的TypedFile類型被私有化了 ,沒法繼續使用1.9的傳方式,所以2.x提供了上傳方案,能夠MultipartBody.Part代替。github
public interface FileUploadService { @Multipart @POST("upload") Call<ResponseBody> upload(@Part("description") RequestBody description, @Part MultipartBody.Part file); }
具體用法。web
先看一個基本的用法:json
// 建立 RequestBody,用於封裝構建RequestBody RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part 和後端約定好Key,這裏的partName是用image MultipartBody.Part body = MultipartBody.Part.createFormData("image", file.getName(), requestFile); // 添加描述 String descriptionString = "hello, 這是文件描述"; RequestBody description = RequestBody.create( MediaType.parse("multipart/form-data"), descriptionString); // 執行請求 Call<ResponseBody> call = service.upload(description, body); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("Upload error:", t.getMessage()); } }); }
@Multipart @POST("you methd url upload/") Call<ResponseBody> uploadFile( @Part() RequestBody file);
或者 :後端
@Multipart @POST() Observable<ResponseBody> uploads( @Url String url, @Part() MultipartBody.Part file);
@POST("upload/") Call<ResponseBody> uploadFiles(@Part("filename") String description, @Part("pic\"; filename=\"image1.png") RequestBody imgs1, @Part("pic\"; filename=\"image2.png") RequestBody imgs2, @Part("pic\"; filename=\"image3.png") RequestBody imgs3, @Part("pic\"; filename=\"image4.png") RequestBody imgs4);
@Multipart @POST() Observable<ResponseBody> uploadFiles( @Url String url, @PartMap() Map<String, RequestBody> maps);
Part方式api
@Multipart @POST("upload/") Call<ResponseBody> register( @FieldMap Map<String , String> usermaps, @Part("avatar\"; filename=\"avatar.jpg") RequestBody avatar, );
擴展一下 將url動態化:緩存
@Multipart @POST Observable<ResponseBody> uploadFileWithPartMap( @Url() String url, @PartMap() Map<String, RequestBody> partMap, @Part("file") MultipartBody.Part file);
注意若是你用retrofit2.0以上的版本請看下面姿式,不然會以下拋異常!MultipartBody.Part的參數不能指定part() 的Key。服務器
java.lang.IllegalArgumentException: @Part parameters using the MultipartBody.Part must not include a part name in the annotation. (parameter #2)
@Multipart @POST Observable<ResponseBody> uploadFileWithPartMap( @Url() String url, @PartMap() Map<String, RequestBody> partMap, @Part MultipartBody.Part file);
java代碼:微信
String token ="dsdsddadad244"; RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); // MultipartBody.Part is used to send also the actual file name MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestFile); // create a map of data to pass along RequestBody tokenBody = RequestBody.create( MediaType.parse("multipart/form-data"), token); HashMap<String, RequestBody> map = new HashMap<>(); map.put("token", tokenBody); Call<ResponseBody> call = service.uploadFileWithPartMap(url, requestBody ); // 執行 call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("Upload error:", t.getMessage()); } });
更簡單的用Body方式:
@POST() Call<ResponseBody> upLoad( @Url() String url, @Body RequestBody Body);
若是支持RxJava就是:
@POST() Observable<ResponseBody> upLoad( @Url() String url, @Body RequestBody Body); ```` Java代碼: //構建body RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM) .addFormDataPart("name", name) .addFormDataPart("psd", psd) .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file)) .build(); //若是和rxjava1.x , call就換成 Observable Call<ResponseBody> call = service.upload(url, requestBody ); // 執行 call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("Upload error:", t.getMessage()); } }); 此種方式讓你很好的解決了用戶**註冊**問題,包含用戶所有的信息和頭像,完美解決你想用表單一塊兒將文字和圖片一塊兒提交的狀況! # 表單提交 # 不少時候想用表單的方式: @Multipart @POST("upload/") Call<ResponseBody> register( @Body RequestBody body ); Java代碼: RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file); Call<ResponseBody> call = service.register(body); Response<ResponseBody> response = call.execute(); ##Json提交 **上傳Json** @POST("/uploadJson") Observable<ResponseBody> uploadjson( @Body RequestBody jsonBody); **upLoadJson 也能夠具體指明Content-Type 爲 「application/json」格式的** 具體組裝咱們的RequestBody則能夠這樣: RequestBody body= RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), jsonString); 接着能夠這樣調用: // 執行請求 Call<ResponseBody> call = service.uploadJson(description, body); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { Log.v("Upload", "success"); } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.e("Upload error:", t.getMessage()); } }); } 至於服務器返回什麼類型的**model**, 開發者能夠自定義, 譬如你能夠把APi 中的 ResponseBody 指定爲你本身的`javaBean`, 固然上層構建Call時候,`Callback`也必須是 `Call<MyBean>` @POST("/uploadJson") Call<MyBean> uploadjson( @Body RequestBody jsonBody); 仔細的朋友會發現有的地方用Call,有的地方用Observable,若是結合了RxJava就是用後者接收了,這裏不關乎什麼方式。 上面的代碼片斷中顯示的代碼初始化(RequestBody 和description), 以及如何使用文件上傳API。正如剛開始已經提到的, 從OkHttp 的RequestBody類中,須要兩個RequestBody.create()方法 除了Body描述, 必須將添加文件包裝成MultipartBody的實例。這就是你須要使用適當的從客戶端上傳文件到服務端。此外, 您能夠添加createFormData中的uploadFile(Uri fileUri)方法,適合相機拍照回來上傳圖片的場景。 public static File getFile(Context context, Uri uri) { if (uri != null) { String path = getPath(context, uri); if (path != null && isLocal(path)) { return new File(path); } } return null; } 經過以上代碼片斷,能夠構造本身的file, 其餘構建ResquestBody的步驟同上所示,以上案列總有一款適合你的web後端。 設置 Content-Type ========================= 請注意設置的內容類型。若是你攔截底層OkHttp客戶端和更改內容類型爲application / json, 你的服務器可能反序列化過程出現的問題。請確保你沒有自定義更改multipart/form-data。 **upLoad圖片也能夠具體指明Content-Type 爲 「image/jpg」格式的** RequestBody requestFile = RequestBody.create(MediaType.parse("image/jpg"), mFile); 上傳文件到服務端示例 ====================================== 若是你已經有你的後端項目, 您能夠依靠下面的示例代碼。咱們使用一個簡單api 上傳到服務器。此外咱們告訴api 傳入參數的請求, 由於咱們使用的是Node.js 解析的回調函數,咱們記錄每一個字段來顯示其輸出。 method: 'POST', path: '/upload', config: { payload: { maxBytes: 209715200, output: 'stream', parse: false }, handler: function(request, reply) { var multiparty = require('multiparty'); var form = new multiparty.Form(); form.parse(request.payload, function(err, fields, files) { console.log(err); console.log(fields); console.log(files); return reply(util.inspect({fields: fields, files: files})); }); }} Android客戶端收到返回類型的字符串, 咱們將接收到的上傳成功的狀態的回調。固然你能夠處理也能夠不處理狀態。下面你將看到一個成功的請求的輸出端和有效載荷的解析。第一個空對象。以後,你能夠看到字段只描述做爲請求的一部分。接着能夠收到文件描述,文件大小,文件暱稱和保存路徑。 服務器解析有效數據的日誌 ----------------------------- Null { description: [ 'hello, this is description speaking' ] } { picture: [ { fieldName: 'picture', originalFilename: '20160312_095248.jpg', path: '/var/folders/rq/q_m4_21j3lqf1lw48fqttx_80000gn/T/X_sxX6LDUMBcuUcUGDMBKc2T.jpg', headers: [Object], size: 39369 } ] } --------------------------------- 回顧 == 文件上傳是應用程序中必不可卻少的功能, 你能夠將此功能集成在您的應用程序使用。本文指導您完成你的Android程序上報文件到您的後端服務器的第一個步驟。 文件上傳和下載進度實現,請繼續關注後續文章! **源碼:[https://github.com/Tamicer/Novate](https://github.com/Tamicer/Novate)** Retrofit 2.0系列請閱讀簡書 更多技術文章請關注碼小白 **Retrofit 2.0+RxJava系列請閱讀** - [Retrofit 2.0(一) 超能實踐,完美支持Https傳輸](http://blog.csdn.net/sk719887916/article/details/51597816) - [Retrofit2.0(二) 完美同步Cookie實現免登陸](http://blog.csdn.net/sk719887916/article/details/51700659) - [Retrofit 2.0 超能實踐(三),輕鬆實現文件/圖片上傳](http://blog.csdn.net/sk719887916/article/details/51700659) - [Retrofit 2.0 超能實踐(四),完成大文件斷點下載](http://www.jianshu.com/p/582e0a4a4ee9) - [基於Retrofit2.0+RxJava 封裝的超好用的RetrofitClient工具類(六)](http://blog.csdn.net/sk719887916/article/details/51958010) - [玩轉IOC,教你徒手實現自定義的Retrofit框架(七)](http://blog.csdn.net/sk719887916/article/details/51957819) - [Retrofit,Okhttp對每一個Request統一動態添加header和參數(五)](http://blog.csdn.net/sk719887916/article/details/52132106) - [Rxjava和Retrofit 須要掌握的幾個實用技巧,緩存問題和統一對有無網絡處理問題(八)](http://blog.csdn.net/sk719887916/article/details/52132106) - [Novate:對Retrofit2.0的又一次完美改進增強!(九)](http://blog.csdn.net/sk719887916/article/details/52195428) 第一時間獲取技術文章請關注微信公衆號! ![開發者技術前線](http://upload-images.jianshu.io/upload_images/2022038-a7b567ef3a0b0d1f.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) >Tamic : http://www.jianshu.com/users/3bbb1ddf4fd5/