這篇文章將為大家詳細(xì)講解有關(guān)Retrofit2.0怎么實(shí)現(xiàn)圖文上傳,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)建站主要企業(yè)基礎(chǔ)官網(wǎng)建設(shè),電商平臺(tái)建設(shè),移動(dòng)手機(jī)平臺(tái),小程序開(kāi)發(fā)等一系列專(zhuān)為中小企業(yè)按需制作網(wǎng)站產(chǎn)品體系;應(yīng)對(duì)中小企業(yè)在互聯(lián)網(wǎng)運(yùn)營(yíng)的各種問(wèn)題,為中小企業(yè)在互聯(lián)網(wǎng)的運(yùn)營(yíng)中保駕護(hù)航。
最近項(xiàng)目里用到了類(lèi)似圖文上傳的功能,以前都是封裝OkHttp的文件上傳功能,這次想換個(gè)姿勢(shì),想用Retrofit2.0實(shí)現(xiàn)這樣的功能,本來(lái)以為挺簡(jiǎn)單的,沒(méi)想到進(jìn)入了深坑,連續(xù)調(diào)整了好幾種姿勢(shì)都報(bào)了同一個(gè)錯(cuò),接著網(wǎng)上類(lèi)似的文章找了一大推,講得都是模棱兩可,或者對(duì)多參數(shù)格式不夠友好,最后還是去看了相關(guān)的源碼,自己把這個(gè)問(wèn)題提出來(lái)解決了,在這里記錄一下。
一、定義網(wǎng)絡(luò)請(qǐng)求接口
public interface GoodsReturnApiService { @Multipart @POST(Compares.GOODS_RETURN_POST) //這里是自己post文件的地址 Observable<GoodsReturnPostEntity> postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts); }
上面定義了一個(gè)接口用于上傳文件請(qǐng)求,有幾個(gè)注解需要說(shuō)明一下, @Multipart這是Retrofit專(zhuān)門(mén)用于文件上傳的注解,需要配合@POST一起使用。
方法postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts)第一個(gè)參數(shù)使用注解@PartMap用于多參數(shù)的情況,如果是單個(gè)參數(shù)也可使用注解@Part。
在類(lèi)型Map<String, RequestBody>中,Map第一個(gè)泛型String是服務(wù)器接收用于文件上傳參數(shù)字段的Key,第二個(gè)泛型RequestBody是OkHttp3包裝的上傳參數(shù)字段的Value,這也是圖文上傳成功的關(guān)鍵所在。在后面會(huì)具體說(shuō)到。
第二個(gè)參數(shù)使用注解@Part用于文件上傳,多文件上傳使用集合類(lèi)型List<MultipartBody.Part>,單文件可以使用類(lèi)型MultipartBody.Part,具體的使用同樣后面講。
這里著重說(shuō)明一下,postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts)方法參數(shù)這樣寫(xiě)純屬個(gè)人習(xí)慣,你也可以直接使用一個(gè)參數(shù)postGoodsReturnPostEntitys(@PartMap Map<String, RequestBody> map),不過(guò)后面對(duì)RequestBody的處理方式也要跟著變化,這里就不詳細(xì)說(shuō)了,只會(huì)介紹上面這種簡(jiǎn)便清晰的方式。
二、初始化Retrofit
public class HttpRequestClient { public static final String TAG = "HttpRequestClientTAG"; private static Retrofit retrofit; private static OkHttpClient getOkHttpClient() { //日志顯示級(jí)別 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封裝比較簡(jiǎn)陋,為的是查看網(wǎng)絡(luò)攔截,就不詳細(xì)說(shuō)了。
三、發(fā)起文件上傳請(qǐng)求
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 path2 = Environment.getExternalStorageDirectory() + File.separator + "test1.jpg"; String path3 = Environment.getExternalStorageDirectory() + File.separator + "test1.jpg"; List<File> fileList = new ArrayList<>(); fileList.add(new File(path2)); fileList.add(new File(path3)); 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ù)自己項(xiàng)目的業(yè)務(wù)需求改變。
下面是上傳文件成功第一個(gè)關(guān)鍵,對(duì)參數(shù)請(qǐng)求頭(姑且叫這個(gè)名字,對(duì)應(yīng)Retrofit上傳文件時(shí)參數(shù)那部分請(qǐng)求頭,下文件(圖片)請(qǐng)求頭同理,對(duì)應(yīng)文件那部分請(qǐng)求頭)的content-type賦值,使用convertToRequestBody()方法。
private RequestBody convertToRequestBody(String param){ RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), param); return requestBody; }
因?yàn)镚sonConverterFactory.create()轉(zhuǎn)換器的緣故,會(huì)將參數(shù)請(qǐng)求頭的content-type值默認(rèn)賦值application/json,如果沒(méi)有進(jìn)行這步轉(zhuǎn)換操作,就可以在OKHttp3的日志攔截器中查看到這樣的賦值,這樣導(dǎo)致服務(wù)器不能正確識(shí)別參數(shù),導(dǎo)致上傳失敗,所以這里需要對(duì)參數(shù)請(qǐng)求頭的content-type設(shè)置一個(gè)正確的值:text/plain。
下面是上傳文件成功第二個(gè)關(guān)鍵的地方,將文件(圖片)請(qǐng)求頭的content-type使用方法filesToMultipartBodyParts()對(duì)其賦值"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; }
關(guān)于“Retrofit2.0怎么實(shí)現(xiàn)圖文上傳”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
當(dāng)前標(biāo)題:Retrofit2.0怎么實(shí)現(xiàn)圖文上傳
本文網(wǎng)址:http://muchs.cn/article10/jojcgo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、、小程序開(kāi)發(fā)、網(wǎng)站策劃、建站公司、營(yíng)銷(xiāo)型網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)