close
当前位置: 物联网在线 > 技术文库 > android >

Android Retrofit 实现文字(参数)和多张图片一起上传

Retrofit普及后,最近好多人都在问,如何实现Retrofit上传多文件+文字需求(朋友圈发图片+文字)

解决方案

google: retrofit upload multiple files

说重点

与其直接说答案,不如我们花点时间说说多文件上传的原理,这样,以后就算出了其他的http框架,你也能快速实现。

HTTP协议就不讲了吧?反正copy一段过来也不会有人看。我们就直接跳到文件上传去。想看也可以,传送门

post form 表单

上图是不是很常见,在网页里选一个文件,点击上传。上传到哪里?服务器咯。web和移动端本质上有区别嘛?木有啊,就是一个前端展示的client。那服务器会为移动端创造一套独立的API嘛?显然他没那么傻。

这个文件上传经常会伴随着其他fields一起上传。可以简单理解为表单上传。

先来看下,如果没有文件,也不用json,单独上传一些key value怎么做?在Postman里可以这样模拟。

Android Retrofit 实现文字(参数)和多张图片一起上传

表单上传要注意的是

content-type设为application/x-www-form-urlencoded

form表单在streaming时是"weibo=stay4it&wechat=stay4it&qq=104816053"

多文件上传

实际上,多文件上传与form表单是一回事,一个key对应一个value。文件上传就是文件名key对应文件byte[] value,如下图postman模拟请求

Android Retrofit 实现文字(参数)和多张图片一起上传

只是如何标记一个key value的开始结束呢?用&分割肯定不够用啦。那就得用个特殊的boudary来做为分隔符。

另外,这个content-type得为multiple/form-data

好了。科普到此结束。简单理解HTTP协议以及form表单概念,相信接下来的代码你就不只是会调用,还能明白为什么。

最原始的上传方式

以前大家都用HttpUrlConnection,Stay在自己动手写HTTP框架-19课时详细讲过如何上传多文件以及进度更新。这里贴下核心代码:

Android Retrofit 实现文字(参数)和多张图片一起上传

以上这个UploadUtil,拿到outputstream,分别写入postContent以及List<FileEntity>,代码不多,相信大家都能看明白。

抓个包看看

请求数据抓包

Android Retrofit 实现文字(参数)和多张图片一起上传

上传的有两个form,
一个content-type为text/plain key为data, value为stay4it。
一个content-type为image/png key为file0, value为文件的bytes

服务器如何接收的?(PHP版)

Android Retrofit 实现文字(参数)和多张图片一起上传

代码还算好懂,$_FILES就是请求上传的多文件,只要content-type设置为multiple/form-data,服务器接收是就会将其当成文件处理,将文件接收在$_FILES中,等待处理(存数据库,存硬盘或转七牛云等等),$this->data是表单中key为data所对应的valuestay4it。(以后再有服务器er告诉你分两个API上传,你就可以这么怼他了: )

返回结果抓包

Android Retrofit 实现文字(参数)和多张图片一起上传

好了,原始的方式聊的差不多了,虽然代码看起来很多,但已经是个util类了,倒不是那么难用。但是我们还是希望在写代码时能尽可能少的去关注内部实现啊。什么multiple/form-data,什么boundary。真是很麻烦嘛。

鸟枪换大炮吧

以下Retrofit多文件上传内容由一叶飘舟大神提供。

Retrofit实现文件和图片一起上传

如果对retrofit不是很了解,参考:初识Retrofit

定义接口

根据对Stay自己动手写HTTP框架-19课时提供的上传图片接口的大量抓包和测试总结,接口定义如下:

Android Retrofit 实现文字(参数)和多张图片一起上传

这里用到了@Partmap注解,将图片文件信息放入map中。

准备图片

在sdcard根目录存放两张图片,分别为test.png和test.jpg(不要是gif图片啊,服务器不支持)

代码实现

这里就不贴代码了,截图如下(如果看不清,鼠标右键在新窗口打开就可以看到原图了):

Android Retrofit 实现文字(参数)和多张图片一起上传

关键代码在于:

看到这个是不是想起了上面我们提到的关键代码呢?下面再贴出来我们对比下。

只要将对应的http请求头信息填写正确,就能上传成功。

那么问题又来了,怎么分析和正确拼写这个请求头呢?

在文章开头的时候有个抓包信息:

Content-Disposition: form-data;; filename="test.png"

实质上上传文件Requestbody对应的请求头就是 name="file0"; filename="test.png",只要拼对了就没有问题了。

注意:

name="file0"; filename="test.png"这个请求头是根据有心课堂提供的上传接口写的,不适用其他上传接口,但原理是类似的;

单张图片上传通用的请求头是:name="file"; filename="test.png"

filename="test.png"这个一般是指(你希望)保存在服务器的文件名字。

举例说明

比如我们这样写请求头信息,如下代码所示:

运行请求抓包请求头信息如下图所示:

Android Retrofit 实现文字(参数)和多张图片一起上传

出现了name="name="file1"这样的字段,拼接错误(不用加name字段),服务器也毫不留情的返回了错误:

Android Retrofit 实现文字(参数)和多张图片一起上传

这个问题我当初没有发现,后来还是请教了Stay才搞明白了。

好了,不知道我讲的大家明白了没有,最后来个成功运行的请求抓包截图吧:

Android Retrofit 实现文字(参数)和多张图片一起上传

关于文字类参数上传

写到最后忘了说文字参数了,文字参数相对文件来说容易些。


(责任编辑:ioter)

用户喜欢...

Android Weekly #276 安卓开发周刊 中文版

您是否了解过Android的Lifecycle-Aware库?(android.jlelse.eu) 我们如何了解Lifecycle-Aware库代码? Nishant Srivastava展示了可以跟踪活动或Lifecycle-Aware的Lifecycle Arch组件的片段,并相应地调整其行为。 为Mos...


Android Weekly #275 安卓开发周刊 中文版

MapMe — Android地图适配器 (medium.com) Josh Burton介绍MapMe,是一个用Kotlin编写的Android库,可以将适配器模式带到地图上。 赞助 CloudRail - 连接到API 10x更快 (cloudrail.com) 当我们用单一的界面连接到所...


使用Android Studio开发可独立运行(runnable)混淆过的Jar程序

之前开发Java程序一直都是使用Eclipse 开发Jar程序,现在开发基本上都已经弃用Eclipse了,但是有时偶尔开发个小的Jar程序,还要切换回去好麻烦,刚好前几天有人问几个相关的问题,就顺便整...


Android Weekly #274 安卓开发周刊 中文版

探索Android Oreo上的别后执行限制(medium.com) 在这篇文章中,Joe Birch解释了关于Android Oreo在后台运行服务的变化。 non-Time领主的time – 第5部分 (blog.stylingandroid.com) Mark Allison继续分析JSR 310 date和...


Android Weekly #273 安卓开发周刊 中文版

开源你的Android代码(android.jlelse.eu) 通过您的开源Android代码,您将(希望地)为Android社区提供有价值的代码,收到建设性的反馈,并与您最初建立的内容进行协作从而使您的代码变得更好。这...


Android Weekly #272 安卓开发周刊 中文版

Android Dev 101:每个初学者都应该知道的一些做法() 看一些初学者或媒介等级开发人员(不要错过任何人)应该知道的一些做法,以便更好地摆脱Android框架。 99.9% crash free sessions (medium.com) Chr...


Android Weekly #271 安卓开发周刊 中文版

依赖注入检查(medium.com) 在本文中,MihályNagy引入了依赖注入检查,一种开源注释处理器,可帮助您解决一些出现在所有JSR 330 DI库中常见的问题。 使用Android Studio插件提高效率 (blog.mindorks.com...


Android Weekly #270 安卓开发周刊 中文版

带有RxJava2的SOLID Android分析 (medium.com) 在这篇文章中,Aris Papadopoulos将解释如何正确创建一个分析系统,同时遵循SOLID原则,并使用RxJava2来解决问题。 (blog.stylingandroid.com) Java中的编程时间很难...


Android内存泄漏思考

Android内存泄漏是一个经常要遇到的问题,程序在内存泄漏的时候很容易导致OOM的发生。那么如何查找内存泄漏和避免内存泄漏就是需要知晓的一个问题,首先我们需要知道一些基础知识。...


Android Weekly #269 安卓开发周刊 中文版

在Google上快速提出操作 () Wolfram Rittmeyer分享了开始在Google上快速创建操作所需的所有信息(为了家庭与助理)。 RxJava中的错误处理(rongi.github.io) 一旦开始编写RxJava代码,你就会意识到有些事...