Android Retrofit实现多图片/文件、图文上传功能
什么是Retrofit?
Retrofit是Square开发的一个Android和Java的REST客户端库。这个库非常简单并且具有很多特性,相比其他的网络库,更容易让初学者快速掌握。它可以处理GET、POST、PUT、DELETE…等请求,还可以使用picasso加载图片。
一、再次膜拜下Retrofit
Retrofit无论从性能还是使用方便性上都很屌!!!,本文不去介绍其运作原理(虽然很想搞明白),后面会出专题文章解析Retrofit的内部原理;本文只是从使用上解析Retrofit实现多图片/文件、图文上传的功能。
二、概念介绍
1)注解@Multipart
从字面上理解就是与多媒体文件相关的,没错,图片、文件等的上传都要用到该注解,其中每个部分需要使用@Part来注解。。看其注释
/** *Denotesthattherequestbodyismulti-part.Partsshouldbedeclaredasparametersand *annotatedwith{@linkPart@Part}. */
2)注解@PartMap
当然可以理解为使用@PartMap注释,传递多个Part,以实现多文件上传。注释
/** *Denotesnameandvaluepartsofamulti-partrequest. **Valuesofthemaponwhichthisannotationexistswillbeprocessedinoneoftwoways: *
-
*
- Ifthetypeis{@linkokhttp3.RequestBodyRequestBody}thevaluewillbeused *directlywithitscontenttype. *
- Otherobjecttypeswillbeconvertedtoanappropriaterepresentationbyusing *{@linkplainConverteraconverter}. *
*
*@Multipart
*@POST("/upload")
*Callupload(
*@Part("file")RequestBodyfile,
*@PartMapMapparams);
*
**A{@codenull}valueforthemap,asakey,orasavalueisnotallowed. * *@seeMultipart *@seePart */
3)RequestBody
从上面注释中就可以看到参数类型是RequestBody,其就是请求体。文件上传就需要参数为RequestBody。官方使用说明如下http://square.github.io/retrofit/
MultipartpartsuseoneofRetrofit'sconvertersortheycanimplementRequestBodytohandletheirownserialization.
四、基本实现
了解了以上概念,下面就一一实现
1)接口定义
publicinterfaceIHttpService{ @Multipart @POST("nocheck/file/agree.do") CallupLoadAgree(@PartMapMap params); }
BaseBean是根据服务端返回数据进行定义的,这个使用时可以根据自有Server定义。
2)Retrofit实现
/** *CreatedbyDELLon2017/3/16. *上传文件用(包含图片) */ publicclassRetrofitHttpUpLoad{ /** *超时时间60s */ privatestaticfinallongDEFAULT_TIMEOUT=60; privatevolatilestaticRetrofitHttpUpLoadmInstance; publicRetrofitmRetrofit; publicIHttpServicemHttpService; privateMapparams=newHashMap (); privateRetrofitHttpUpLoad(){ mRetrofit=newRetrofit.Builder() .baseUrl(UrlConfig.ROOT_URL) .client(genericClient()) .addConverterFactory(GsonConverterFactory.create()) .build(); mHttpService=mRetrofit.create(IHttpService.class); } publicstaticRetrofitHttpUpLoadgetInstance(){ if(mInstance==null){ synchronized(RetrofitHttpUpLoad.class){ if(mInstance==null) mInstance=newRetrofitHttpUpLoad(); } } returnmInstance; } /** *添加统一超时时间,http日志打印 * *@return */ publicstaticOkHttpClientgenericClient(){ HttpLoggingInterceptorlogging=newHttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClienthttpClient=newOkHttpClient.Builder() .addInterceptor(logging) .connectTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS) .writeTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS) .build(); returnhttpClient; } /** *将call加入队列并实现回调 * *@paramcall调入的call *@paramretrofitCallBack回调 *@parammethod调用方法标志,回调用 *@param 泛型参数 */ publicstatic voidaddToEnqueue(Call call,finalRetrofitCallBackretrofitCallBack,finalintmethod){ finalContextcontext=MyApplication.getContext(); call.enqueue(newCallback (){ @Override publicvoidonResponse(Call call,Response response){ LogUtil.d("retrofitbackcode===="+response.code()); if(null!=response.body()){ if(response.code()==200){ LogUtil.d("retrofitbackbody===="+newGson().toJson(response.body())); retrofitCallBack.onResponse(response,method); }else{ LogUtil.d("toEnqueue,onResponseFail:"+response.code()); ToastUtil.makeShortText(context,"网络连接错误"+response.code()); retrofitCallBack.onFailure(response,method); } }else{ LogUtil.d("toEnqueue,onResponseFailm:"+response.message()); ToastUtil.makeShortText(context,"网络连接错误"+response.message()); retrofitCallBack.onFailure(response,method); } } @Override publicvoidonFailure(Call call,Throwablet){ LogUtil.d("toEnqueue,onResponseFailunKnown:"+t.getMessage()); t.printStackTrace(); ToastUtil.makeShortText(context,"网络连接错误"+t.getMessage()); retrofitCallBack.onFailure(null,method); } }); } /** *添加参数 *根据传进来的Object对象来判断是String还是File类型的参数 */ publicRetrofitHttpUpLoadaddParameter(Stringkey,Objecto){ if(oinstanceofString){ RequestBodybody=RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"),(String)o); params.put(key,body); }elseif(oinstanceofFile){ RequestBodybody=RequestBody.create(MediaType.parse("multipart/form-data;charset=UTF-8"),(File)o); params.put(key+"\";filename=\""+((File)o).getName()+"",body); } returnthis; } /** *构建RequestBody */ publicMap bulider(){ returnparams; } }
其中定义了Retrofit实例、还用拦截器定义了统一的超时时间和日志打印;将call加入队列并实现回调。最重要的就是添加参数:
/***添加参数 *根据传进来的Object对象来判断是String还是File类型的参数 */ publicRetrofitHttpUpLoadaddParameter(Stringkey,Objecto){ if(oinstanceofString){ RequestBodybody=RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"),(String)o); params.put(key,body); }elseif(oinstanceofFile){ RequestBodybody=RequestBody.create(MediaType.parse("multipart/form-data;charset=UTF-8"),(File)o); params.put(key+"\";filename=\""+((File)o).getName()+"",body); } returnthis; }
这里就是根据传入的参数,返回不同的RequestBody。
3)使用
privatevoidupLoadAgree(){ showWaitDialog(); RetrofitHttpUpLoadretrofitHttpUpLoad=RetrofitHttpUpLoad.getInstance(); if(!StringUtil.isEmpty(pathImage[0])){ retrofitHttpUpLoad=retrofitHttpUpLoad.addParameter("pic1",newFile(pathImage[0])); } if(!StringUtil.isEmpty(pathImage[1])){ retrofitHttpUpLoad=retrofitHttpUpLoad.addParameter("pic2",newFile(pathImage[1])); } if(!StringUtil.isEmpty(pathImage[2])){ retrofitHttpUpLoad=retrofitHttpUpLoad.addParameter("zip",newFile(pathImage[2])); } Mapparams=retrofitHttpUpLoad .addParameter("status","4") .addParameter("pickupId",tv_orderquality_pid.getText().toString()) .addParameter("cause",reason) .addParameter("connectname",et_orderquality_lxrname.getText().toString()) .addParameter("connectphone",et_orderquality_lxrphone.getText().toString()) .addParameter("details",et_orderquality_xqms.getText().toString()) .bulider(); RetrofitHttpUpLoad.addToEnqueue(RetrofitHttpUpLoad.getInstance().mHttpService.upLoadAgree(params), this,HttpStaticApi.HTTP_UPLOADAGREE); }
需要注意的是要对图片及文件路径进行判空操作,负责会报异常W/System.err:java.io.FileNotFoundException:/:openfailed:EISDIR(Isadirectory)
以上所述是小编给大家介绍的Android基于Retrofit实现多图片/文件、图文上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!