Android Retrofit实现多图片/文件、图文上传功能
发布时间 - 2026-01-11 00:14:11 点击率:次什么是 Retrofit ?

Retrofit是Square开发的一个Android和Java的REST客户端库。这个库非常简单并且具有很多特性,相比其他的网络库,更容易让初学者快速掌握。它可以处理GET、POST、PUT、DELETE…等请求,还可以使用picasso加载图片。
一、再次膜拜下Retrofit
Retrofit无论从性能还是使用方便性上都很!!!,本文不去介绍其运作原理(虽然很想搞明白),后面会出专题文章解析Retrofit的内部原理;本文只是从使用上解析Retrofit实现多图片/文件、图文上传的功能。
二、概念介绍
1)注解@Multipart
从字面上理解就是与多媒体文件相关的,没错,图片、文件等的上传都要用到该注解,其中每个部分需要使用@Part来注解。。看其注释
/**
* Denotes that the request body is multi-part. Parts should be declared as parameters and
* annotated with {@link Part @Part}.
*/
2)注解@PartMap
当然可以理解为使用@PartMap注释,传递多个Part,以实现多文件上传。注释
/**
* Denotes name and value parts of a multi-part request.
* <p>
* Values of the map on which this annotation exists will be processed in one of two ways:
* <ul>
* <li>If the type is {@link okhttp3.RequestBody RequestBody} the value will be used
* directly with its content type.</li>
* <li>Other object types will be converted to an appropriate representation by using
* {@linkplain Converter a converter}.</li>
* </ul>
* <p>
* <pre><code>
* @Multipart
* @POST("/upload")
* Call<ResponseBody> upload(
* @Part("file") RequestBody file,
* @PartMap Map<String, RequestBody> params);
* </code></pre>
* <p>
* A {@code null} value for the map, as a key, or as a value is not allowed.
*
* @see Multipart
* @see Part
*/
3)RequestBody
从上面注释中就可以看到参数类型是RequestBody,其就是请求体。文件上传就需要参数为RequestBody。官方使用说明如下http://square.github.io/retrofit/
Multipart parts use one of Retrofit's converters or they can implement RequestBody to handle their own serialization.
四、基本实现
了解了以上概念,下面就一一实现
1)接口定义
public interface IHttpService {
@Multipart
@POST("nocheck/file/agree.do")
Call<BaseBean> upLoadAgree(@PartMap Map<String, RequestBody>params);
}
BaseBean是根据服务端返回数据进行定义的,这个使用时可以根据自有Server定义。
2)Retrofit实现
/**
* Created by DELL on 2017/3/16.
* 上传文件用(包含图片)
*/
public class RetrofitHttpUpLoad {
/**
* 超时时间60s
*/
private static final long DEFAULT_TIMEOUT = 60;
private volatile static RetrofitHttpUpLoad mInstance;
public Retrofit mRetrofit;
public IHttpService mHttpService;
private Map<String, RequestBody> params = new HashMap<String, RequestBody>();
private RetrofitHttpUpLoad() {
mRetrofit = new Retrofit.Builder()
.baseUrl(UrlConfig.ROOT_URL)
.client(genericClient())
.addConverterFactory(GsonConverterFactory.create())
.build();
mHttpService = mRetrofit.create(IHttpService.class);
}
public static RetrofitHttpUpLoad getInstance() {
if (mInstance == null) {
synchronized (RetrofitHttpUpLoad.class) {
if (mInstance == null)
mInstance = new RetrofitHttpUpLoad();
}
}
return mInstance;
}
/**
* 添加统一超时时间,http日志打印
*
* @return
*/
public static OkHttpClient genericClient() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder()
.addInterceptor(logging)
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.build();
return httpClient;
}
/**
* 将call加入队列并实现回调
*
* @param call 调入的call
* @param retrofitCallBack 回调
* @param method 调用方法标志,回调用
* @param <T> 泛型参数
*/
public static <T> void addToEnqueue(Call<T> call, final RetrofitCallBack retrofitCallBack, final int method) {
final Context context = MyApplication.getContext();
call.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
LogUtil.d("retrofit back code ====" + response.code());
if (null != response.body()) {
if (response.code() == 200) {
LogUtil.d("retrofit back body ====" + new Gson().toJson(response.body()));
retrofitCallBack.onResponse(response, method);
} else {
LogUtil.d("toEnqueue, onResponse Fail:" + response.code());
ToastUtil.makeShortText(context, "网络连接错误" + response.code());
retrofitCallBack.onFailure(response, method);
}
} else {
LogUtil.d("toEnqueue, onResponse Fail m:" + response.message());
ToastUtil.makeShortText(context, "网络连接错误" + response.message());
retrofitCallBack.onFailure(response, method);
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {
LogUtil.d("toEnqueue, onResponse Fail unKnown:" + t.getMessage());
t.printStackTrace();
ToastUtil.makeShortText(context, "网络连接错误" + t.getMessage());
retrofitCallBack.onFailure(null, method);
}
});
}
/**
* 添加参数
* 根据传进来的Object对象来判断是String还是File类型的参数
*/
public RetrofitHttpUpLoad addParameter(String key, Object o) {
if (o instanceof String) {
RequestBody body = RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"), (String) o);
params.put(key, body);
} else if (o instanceof File) {
RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data;charset=UTF-8"), (File) o);
params.put(key + "\"; filename=\"" + ((File) o).getName() + "", body);
}
return this;
}
/**
* 构建RequestBody
*/
public Map<String, RequestBody> bulider() {
return params;
}
}
其中定义了Retrofit实例、还用拦截器定义了统一的超时时间和日志打印;将call加入队列并实现回调。最重要的就是添加参数:
/** * 添加参数
* 根据传进来的Object对象来判断是String还是File类型的参数
*/
public RetrofitHttpUpLoad addParameter(String key, Object o) {
if (o instanceof String) {
RequestBody body = RequestBody.create(MediaType.parse("text/plain;charset=UTF-8"), (String) o);
params.put(key, body);
} else if (o instanceof File) {
RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data;charset=UTF-8"), (File) o);
params.put(key + "\"; filename=\"" + ((File) o).getName() + "", body);
}
return this;
}
这里就是根据传入的参数,返回不同的RequestBody。
3)使用
private void upLoadAgree() {
showWaitDialog();
RetrofitHttpUpLoad retrofitHttpUpLoad = RetrofitHttpUpLoad.getInstance();
if (!StringUtil.isEmpty(pathImage[0])){
retrofitHttpUpLoad = retrofitHttpUpLoad.addParameter("pic1",new File(pathImage[0]));
}
if (!StringUtil.isEmpty(pathImage[1])){
retrofitHttpUpLoad = retrofitHttpUpLoad.addParameter("pic2", new File(pathImage[1]));
}
if (!StringUtil.isEmpty(pathImage[2])){
retrofitHttpUpLoad = retrofitHttpUpLoad.addParameter("zip", new File(pathImage[2]));
}
Map<String, RequestBody> params = 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: /: open failed: EISDIR (Is a directory)
以上所述是小编给大家介绍的Android基于Retrofit实现多图片/文件、图文上传功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# android retrofit 图文上传
# retrofit 多文件上传
# Android使用 Retrofit 2.X 上传多文件和多表单示例
# 基于标准http实现Android多文件上传
# Android中Okhttp3实现上传多张图片同时传递参数
# Android 使用 okhttp3和retrofit2 进行单文件和
# 回调
# 上传
# 多图
# 会报
# 小编
# 文件上传
# 的是
# 还可以
# 多个
# 在此
# 最重要
# 其他的
# 是从
# 不去
# 给大家
# 都很
# 要用
# 可以看到
# 它可以
# 很想
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
什么是javascript作用域_全局和局部作用域有什么区别?
Laravel如何实现登录错误次数限制_Laravel自带LoginThrottles限流配置【方法】
Laravel安装步骤详细教程_Laravel环境搭建指南
PHP 500报错的快速解决方法
如何在服务器上配置二级域名建站?
深圳网站制作平台,深圳市做网站好的公司有哪些?
iOS发送验证码倒计时应用
Laravel队列任务超时怎么办_Laravel Queue Timeout设置详解
浅谈Javascript中的Label语句
如何在万网利用已有域名快速建站?
Laravel怎么在Blade中安全地输出原始HTML内容
如何用IIS7快速搭建并优化网站站点?
Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道
千库网官网入口推荐 千库网设计创意平台入口
JavaScript如何操作视频_媒体API怎么控制播放
SQL查询语句优化的实用方法总结
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
浅谈redis在项目中的应用
极客网站有哪些,DoNews、36氪、爱范儿、虎嗅、雷锋网、极客公园这些互联网媒体网站有什么差异?
如何用AI一键生成爆款短视频文案?小红书AI文案写作指令【教程】
使用spring连接及操作mongodb3.0实例
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
,在苏州找工作,上哪个网站比较好?
Chrome浏览器标签页分组怎么用_谷歌浏览器整理标签页技巧【效率】
微信小程序 wx.uploadFile无法上传解决办法
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
微信小程序 require机制详解及实例代码
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
Internet Explorer官网直接进入 IE浏览器在线体验版网址
详解jQuery中的事件
网站制作软件有哪些,制图软件有哪些?
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
郑州企业网站制作公司,郑州招聘网站有哪些?
如何在香港免费服务器上快速搭建网站?
为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】
Laravel中间件如何使用_Laravel自定义中间件实现权限控制
如何快速查询网址的建站时间与历史轨迹?
Laravel如何使用Blade模板引擎?(完整语法和示例)
弹幕视频网站制作教程下载,弹幕视频网站是什么意思?
百度输入法ai组件怎么删除 百度输入法ai组件移除工具
免费网站制作appp,免费制作app哪个平台好?
如何在橙子建站中快速调整背景颜色?
香港服务器WordPress建站指南:SEO优化与高效部署策略
如何在 React 中条件性地遍历数组并渲染元素
Laravel如何实现多对多模型关联?(Eloquent教程)
javascript日期怎么处理_如何格式化输出
微信小程序 canvas开发实例及注意事项
网站制作价目表怎么做,珍爱网婚介费用多少?
小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像
Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程

