您的位置:首页 > 其它

Retrofit 2.0 轻松实现多文件/图片上传

2016-10-19 17:12 579 查看

使用 Retrofit1.x上传文件

大家都知道在2.0以前版本上传图片的姿势

public interface ApiManager {
@Multipart
@POST("/user/addCarInfo")
void addCarInfo(@QueryMap Map<String, Object> options, @Part("file") TypedFile file, Callback<JsonElement> response);

}

使用 Retrofit 2.X 上传

Retrofit 2上传文件

使用2,0,我们发现TypedFile类型被私有化了 ,无法继续使用1.9的传方式无法再上层调用了,可以MultipartBody.Part代替

public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> upload(@Part("description") RequestBody description,
@Part MultipartBody.Part file);
}

具体用法

// 创建 RequestBody,用于封装 请求RequestBody
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);

// MultipartBody.Part is used to send also the actual file name
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("avatar\\\\"; filename=\\\\"avatar.jpg") RequestBody 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("upload/")
Call<ResponseBody> register(
@Query("name") String cardName,
@Query("phone") String callphone,
@Query("address") String address,
@Part("avatar\\\\"; filename=\\\\"avatar.jpg") RequestBody avatar,
);

此种方式让你很好的解决用户注册问题。包含用户全部信息

上面的代码片段中显示的代码初始化(RequestBody 和description),以及如何使用文件上传服务。正如已经提到的,从OkHttp RequestBody类用于描述。需要两个RequestBody.create()方法

除了描述,必须将添加文件包装成MultipartBody的实例。这就是你需要使用适当的从客户端上传文件。此外,您可以添加createFormData中的uploadFile(Uri fileUri)方法和重用

设置 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}));
});
}}

安卓客户端收到返回类型的字符串, 我们将接收到的上传成功的状态的回调。当然你可以处理也可以不处理。

下面你将看到一个成功的请求的输出端和有效载荷的解析。第一个空对象。之后,你可以看到字段只描述作为请求的一部分。接着可以收到文件描述,文件大小,文件昵称和保存路径。

服务器解析有效数据的日志

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设备上报文件到您的后端服务器的第一个 步骤。

上传出现类型错误解决方案:

其中一定要添加上filename这个

public interface CheckIn {
@Multipart
@POST("/check/checkin.action")
Call<ResponseCode> checkIn(@Part("image\"; filename=\"文件名.jpg") RequestBody file);
}

创建RequestBody对象作为参数上传

RequestBody imgFile = RequestBody.create(MediaType.parse("image/*"), imgFile);


以上方法解决了文件正常上传的问题,但是文件名却只能是常量,固定死了,并不是理想的结果,那么接下来就是解决这个问题。

首先是不需要在interface上定义文件名,而是通过Map来上传所有参数。

参数定义如下:

try {
Staff staff = (Staff) SharedPreferencesUtils.getObject(context,LoginActivity.LOGIN_USER);
RequestBody staffPhone = RequestBody.create(MediaType.parse("text/plain"), staff.getPhone());
RequestBody time = RequestBody.create(MediaType.parse("text/plain"), "时间");
RequestBody address = RequestBody.create(MediaType.parse("text/plain"), "地点");
RequestBody type = RequestBody.create(MediaType.parse("text/plain"), "类型");

Map<String, RequestBody> map = new HashMap<>();
map.put("staffPhone",staffPhone);
map.put("checkTime",time);
map.put("checkAddress",address);
map.put("checkType",type);

if (imgFile != null) {
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), imgFile);
map.put("image\"; filename=\""+imgFile.getName()+"", fileBody);
}

HttpService.checkIn(map);
} catch (IOException e) {
e.printStackTrace();
}

interface如下:

public interface CheckIn{
@Multipart
@POST("/check/checkin.action")
Call<ResponseCode> checkIn(@PartMap Map<String, RequestBody> params);
}


OK,搞定。

文/Tamic(简书作者)

原文链接:http://www.jianshu.com/p/acfefb0a204f

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐