国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Retrofit2.0 實現(xiàn)圖文(參數(shù)+圖片)上傳方法總結(jié)

2019-10-22 18:30:55
字體:
供稿:網(wǎng)友

最近項目里用到了類似圖文上傳的功能,以前都是封裝OkHttp的文件上傳功能,這次想換個姿勢,想用Retrofit2.0實現(xiàn)這樣的功能,本來以為挺簡單的,沒想到進(jìn)入了深坑,連續(xù)調(diào)整了好幾種姿勢都報了同一個錯,接著網(wǎng)上類似的文章找了一大推,講得都是模棱兩可,或者對多參數(shù)格式不夠友好,最后還是去看了相關(guān)的源碼,自己把這個問題提出來解決了,在這里記錄一下。

一、定義網(wǎng)絡(luò)請求接口

public interface GoodsReturnApiService {  @Multipart  @POST(Compares.GOODS_RETURN_POST)  //這里是自己post文件的地址  Observable<GoodsReturnPostEntity> postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts);}

上面定義了一個接口用于上傳文件請求,有幾個注解需要說明一下, @Multipart這是Retrofit專門用于文件上傳的注解,需要配合@POST一起使用。

方法postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts)第一個參數(shù)使用注解@PartMap用于多參數(shù)的情況,如果是單個參數(shù)也可使用注解@Part。

在類型Map<String, RequestBody>中,Map第一個泛型String是服務(wù)器接收用于文件上傳參數(shù)字段的Key,第二個泛型RequestBody是OkHttp3包裝的上傳參數(shù)字段的Value,這也是圖文上傳成功的關(guān)鍵所在。在后面會具體說到。

第二個參數(shù)使用注解@Part用于文件上傳,多文件上傳使用集合類型List<MultipartBody.Part>,單文件可以使用類型MultipartBody.Part,具體的使用同樣后面講。

這里著重說明一下,postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts)方法參數(shù)這樣寫純屬個人習(xí)慣,你也可以直接使用一個參數(shù)postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map),不過后面對RequestBody的處理方式也要跟著變化,這里就不詳細(xì)說了,只會介紹上面這種簡便清晰的方式。

二、初始化Retrofit

public class HttpRequestClient {  public static final String TAG = "HttpRequestClientTAG";  private static Retrofit retrofit;  private static OkHttpClient getOkHttpClient() {    //日志顯示級別    HttpLoggingInterceptor.Level level= HttpLoggingInterceptor.Level.BODY;    //新建log攔截器    HttpLoggingInterceptor loggingInterceptor=new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {      @Override      public void log(String message) {        Log.d(TAG, message);      }    });    loggingInterceptor.setLevel(level);    //定制OkHttp    OkHttpClient.Builder httpClientBuilder = new OkHttpClient        .Builder();    //OkHttp進(jìn)行添加攔截器loggingInterceptor    httpClientBuilder.addInterceptor(loggingInterceptor);    return httpClientBuilder.build();  }  public static Retrofit getRetrofitHttpClient(){    if(null == retrofit){      synchronized (HttpRequestClient.class){        if(null == retrofit){          retrofit = new Retrofit.Builder()              .client(getOkHttpClient())              .baseUrl(Compares.URL)              .addConverterFactory(GsonConverterFactory.create())              .addCallAdapterFactory(RxJava2CallAdapterFactory.create())              .build();        }      }    }    return retrofit;  }}

為了演示,Retrofit封裝比較簡陋,為的是查看網(wǎng)絡(luò)攔截,就不詳細(xì)說了。

三、發(fā)起文件上傳請求

private void postGoodsPicToServer(){    Map<String,RequestBody> params = new HashMap<>();    //以下參數(shù)是偽代碼,參數(shù)需要換成自己服務(wù)器支持的    params.put("type", convertToRequestBody("type"));    params.put("title",convertToRequestBody("title"));    params.put("info",convertToRequestBody("info");    params.put("count",convertToRequestBody("count"));    //為了構(gòu)建數(shù)據(jù),同樣是偽代碼    String path1 = Environment.getExternalStorageDirectory() + File.separator + "test1.jpg";    String path2 = Environment.getExternalStorageDirectory() + File.separator + "test1.jpg";    List<File> fileList = new ArrayList<>();    fileList.add(new File(path1));    fileList.add(new File(path2));    List<MultipartBody.Part> partList = filesToMultipartBodyParts(fileList);    HttpRequestClient.getRetrofitHttpClient().create(GoodsReturnApiService.class)        .postGoodsReturnPostEntitys(params,partList)        .subscribeOn(Schedulers.newThread())        .observeOn(AndroidSchedulers.mainThread())        .subscribe(new Observer<GoodsReturnPostEntity>() {          @Override          public void onSubscribe(@NonNull Disposable d) {          }          @Override          public void onNext(@NonNull GoodsReturnPostEntity goodsReturnPostEntity) {          }          @Override          public void onError(@NonNull Throwable e) {          }          @Override          public void onComplete() {          }        });}

上面的params和fileList都是構(gòu)造的偽代碼,需要根據(jù)自己項目的業(yè)務(wù)需求改變。

下面是上傳文件成功第一個關(guān)鍵,對參數(shù)請求頭(姑且叫這個名字,對應(yīng)Retrofit上傳文件時參數(shù)那部分請求頭,下文件(圖片)請求頭同理,對應(yīng)文件那部分請求頭)的content-type賦值,使用convertToRequestBody()方法。

private RequestBody convertToRequestBody(String param){    RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), param);    return requestBody;  }

因為GsonConverterFactory.create()轉(zhuǎn)換器的緣故,會將參數(shù)請求頭的content-type值默認(rèn)賦值application/json,如果沒有進(jìn)行這步轉(zhuǎn)換操作,就可以在OKHttp3的日志攔截器中查看到這樣的賦值,這樣導(dǎo)致服務(wù)器不能正確識別參數(shù),導(dǎo)致上傳失敗,所以這里需要對參數(shù)請求頭的content-type設(shè)置一個正確的值:text/plain。

下面是上傳文件成功第二個關(guān)鍵的地方,將文件(圖片)請求頭的content-type使用方法filesToMultipartBodyParts()對其賦值"image/png",并返回MultipartBody.Part集合。

private List<MultipartBody.Part> filesToMultipartBodyParts(List<File> files) {    List<MultipartBody.Part> parts = new ArrayList<>(files.size());    for (File file : files) {      RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), file);      MultipartBody.Part part = MultipartBody.Part.createFormData("multipartFiles", file.getName(), requestBody);      parts.add(part);    }    return parts;  }

說到底,還是對參數(shù)請求頭和文件(圖片)請求頭的content-type屬性賦值處理,不要讓Retrofit 默認(rèn)賦值,這里才是關(guān)鍵。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 大庆市| 岳普湖县| 开江县| 宜宾市| 汝州市| 白水县| 马关县| 青冈县| 延川县| 共和县| 南平市| 保山市| 全南县| 筠连县| 平南县| 日照市| 临夏县| 绥德县| 宝应县| 红桥区| 罗定市| 柘城县| 富阳市| 桐乡市| 上栗县| 会泽县| 逊克县| 定南县| 江永县| 沙坪坝区| 皮山县| 鹤峰县| 石台县| 建瓯市| 墨江| 双辽市| 广汉市| 余庆县| 乐清市| 鄂伦春自治旗| 湘乡市|