Android Volley文件上传(一)
2016-04-14 17:38
405 查看
对于Volley的使用这里不做介绍,不清楚的自己找资料了解,我给大家介绍的是使用Volley网络框架来实现上传文件功能,因为volley没有自带上传文件功能,因此只能自己实现。而实现Volley文件上传前,必须了解表单的提交。
看上面数据格式,只需要分析数据如何封装的,因为http请求头已经帮我们封装好了。上面有三条数据,因为都一样,所以只需要分析一条,拿最后一条来分析,因为最后一条保护了结尾符。
第一行
其格式是 “–” + boundary + “\r\n”。”-“是数据开始标志,boundary是为http实体头定义的数据分割线,boundary可以为任意字符,只需要和————Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1中保持一致即可,
“\r\n”是回车换行
第二行
其格式是 “Content-Disposition: form-data; name=” + 参数名称 + “\r\n”。Content-Disposition是上传的内容特性, form-data是以表单形式上传
第三行
其格式是”\r\n”,回车换行
第四行
其格式是 value + “\r\n”。 value是参数的值,参数是由key和value组成
第五行
其格式是“–”+boundary + “–” + “\r\n”
说明:在所有的数据结束之后,需要有这个结尾标志。
如果有多个参数,则重复1、2、3、4,直至最后一个参数的最后加上结尾行。
一、创建表单参数实体类
这里对参数做一个封装,因为往往提交表单的时候,都需要提交多个参数
二、Volley 对数据的封装
1、Volley定制 Request 的时候,需要重写获取实体的方法
2、把参数通过二进制的形式传给服务器,当然就不需要重写获取参数的方法
3、为了简化回调接口,这里把错误回调Response.ErrorListener 和正确的数据回调Response.Listener合并成一个ResponseListener
4、最核心的方法也就在getBody()中,这个方法的实现,如果对表单提交的数据格式很了解,实现起来非常简单,因为这个方法就是把参数拼接成我们所分析的数据格式;
可以看到,这个方法就是实现了对数据的封装
5、 Request 中还有一个关键的地方,需要在 http 头部中声明内容类型为表单数据
所以的重写下面方法为
通过以上内容我们不难发现,表单提交就是把文本通过二进制的形式传给服务器,从而得到对应的响应,这篇 blog 其实也算是一篇过度的文章,因为一般我们不会这么提交文字数据,那什么时候我们需要用到表单提交呢,当表单中含有附件,如图片,视频等文件的的时候;这也就是我们下一篇 blog 要讲的:Android volley 文件上传(二)
(一)表单提交
要了解表单提交必须知道表单提交的数据格式是什么样,从网站抓取一条数据,分析其表单的数据格式Connection: keep-alive Content-Length: 123 X-Requested-With: ShockwaveFlash/16.0.0.296 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.93 Safari/537.36 Content-Type: multipart/form-data; boundary=----------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 Accept: */* Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.8 Cookie: bdshare_firstime=1409052493497 ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 Content-Disposition: form-data; name="position" 1425264476444 ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 Content-Disposition: form-data; name="editorIndex" ue_con_1425264252856 ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 Content-Disposition: form-data; name="cm" 100672 ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--
看上面数据格式,只需要分析数据如何封装的,因为http请求头已经帮我们封装好了。上面有三条数据,因为都一样,所以只需要分析一条,拿最后一条来分析,因为最后一条保护了结尾符。
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1 Content-Disposition: form-data; name="cm" 100672 ------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--
第一行
其格式是 “–” + boundary + “\r\n”。”-“是数据开始标志,boundary是为http实体头定义的数据分割线,boundary可以为任意字符,只需要和————Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1中保持一致即可,
“\r\n”是回车换行
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1
第二行
其格式是 “Content-Disposition: form-data; name=” + 参数名称 + “\r\n”。Content-Disposition是上传的内容特性, form-data是以表单形式上传
Content-Disposition: form-data; name="cm"
第三行
其格式是”\r\n”,回车换行
第四行
其格式是 value + “\r\n”。 value是参数的值,参数是由key和value组成
100672
第五行
其格式是“–”+boundary + “–” + “\r\n”
------------Ij5ei4KM7KM7ae0KM7cH2ae0Ij5Ef1--
说明:在所有的数据结束之后,需要有这个结尾标志。
如果有多个参数,则重复1、2、3、4,直至最后一个参数的最后加上结尾行。
一、创建表单参数实体类
这里对参数做一个封装,因为往往提交表单的时候,都需要提交多个参数
/** * 表单实体类 * Created by Hlh on 2016/4/14. */ public class TextParams { private String name; private String value; public String getName() { return name; } public String getValue() { return value; } public void setName(String name) { this.name = name; } public void setValue(String value) { this.value = value; } }
二、Volley 对数据的封装
/** * Created by Hlh on 2016/4/14. */ public class PostFormRequest extends Request { private ResponseListener mListener; //用来解析 json 用的 private Gson mGson; //在用 gson 解析 json 数据的时候,需要用到这个参数 private Type mClazz; //请求 数据通过参数的形式传入 private List<TextParams> mListItem; //数据分割线 private String BOUNDARY = "---------Hlh"; private String MULTIPART_FORM_DATA = "multipart/form-data"; public PostFormRequest(String url, List<TextParams> listItem, Type type, ResponseListener listener) { super(Method.POST, url, listener); this.mListener = listener; mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); mClazz = type; setShouldCache(false); mListItem = listItem; } /** * 这里开始解析数据 * * @param response Response from the network * @return */ @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { try { T result; String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); result = mGson.fromJson(jsonString, mClazz); return Response.success(result, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } } /** * 回调正确的数据 * * @param response The parsed response returned by */ @Override protected void deliverResponse(T response) { mListener.onResponse(response); } @Override public byte[] getBody() throws AuthFailureError { if (mListItem == null || mListItem.size() == 0) { return super.getBody(); } ByteArrayOutputStream bos = new ByteArrayOutputStream(); int N = mListItem.size(); TextParams TextParams; for (int i = 0; i < N; i++) { TextParams = mListItem.get(i); StringBuffer sb = new StringBuffer(); /*第一行:"--" + boundary + "\r\n" ;*/ sb.append("--" + BOUNDARY); sb.append("\r\n"); /*第二行:"Content-Disposition: form-data; name="参数的名称"" + "\r\n" ;*/ sb.append("Content-Disposition: form-data;"); sb.append("name=\""); sb.append(TextParams.getName()); sb.append("\""); sb.append("\r\n"); /*第三行:"\r\n" ;*/ sb.append("\r\n"); /*第四行:"参数的值" + "\r\n" ;*/ sb.append(TextParams.getValue()); sb.append("\r\n"); try { bos.write(sb.toString().getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); } } /*结尾行:"--" + boundary + "--" + "\r\n" ;*/ String endLine = "--" + BOUNDARY + "--" + "\r\n"; try { bos.write(endLine.toString().getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); } return bos.toByteArray(); } /*获取内容类型,这里为表单类型*/ @Override public String getBodyContentType() { return MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY; } }
1、Volley定制 Request 的时候,需要重写获取实体的方法
public byte[] getBody() throws AuthFailureError {}
2、把参数通过二进制的形式传给服务器,当然就不需要重写获取参数的方法
protected Map<String, String> getParams() throws AuthFailureError {}
3、为了简化回调接口,这里把错误回调Response.ErrorListener 和正确的数据回调Response.Listener合并成一个ResponseListener
public interface ResponseListener<T> extends Response.ErrorListener,Response.Listener<T> {}
4、最核心的方法也就在getBody()中,这个方法的实现,如果对表单提交的数据格式很了解,实现起来非常简单,因为这个方法就是把参数拼接成我们所分析的数据格式;
@Override public byte[] getBody() throws AuthFailureError { if (mListItem == null || mListItem.size() == 0) { return super.getBody(); } ByteArrayOutputStream bos = new ByteArrayOutputStream(); int N = mListItem.size(); TextParams TextParams; for (int i = 0; i < N; i++) { TextParams = mListItem.get(i); StringBuffer sb = new StringBuffer(); /*第一行:"--" + boundary + "\r\n" ;*/ sb.append("--" + BOUNDARY); sb.append("\r\n"); /*第二行:"Content-Disposition: form-data; name="参数的名称"" + "\r\n" ;*/ sb.append("Content-Disposition: form-data;"); sb.append("name=\""); sb.append(TextParams.getName()); sb.append("\""); sb.append("\r\n"); /*第三行:"\r\n" ;*/ sb.append("\r\n"); /*第四行:"参数的值" + "\r\n" ;*/ sb.append(TextParams.getValue()); sb.append("\r\n"); try { bos.write(sb.toString().getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); } } /*结尾行:"--" + boundary + "--" + "\r\n" ;*/ String endLine = "--" + BOUNDARY + "--" + "\r\n"; try { bos.write(endLine.toString().getBytes("utf-8")); } catch (IOException e) { e.printStackTrace(); } return bos.toByteArray(); }
可以看到,这个方法就是实现了对数据的封装
5、 Request 中还有一个关键的地方,需要在 http 头部中声明内容类型为表单数据
Content-Type: multipart/form-data; boundary=----------Hlh
所以的重写下面方法为
public String getBodyContentType() { return MULTIPART_FORM_DATA+"; boundary="+BOUNDARY; }
通过以上内容我们不难发现,表单提交就是把文本通过二进制的形式传给服务器,从而得到对应的响应,这篇 blog 其实也算是一篇过度的文章,因为一般我们不会这么提交文字数据,那什么时候我们需要用到表单提交呢,当表单中含有附件,如图片,视频等文件的的时候;这也就是我们下一篇 blog 要讲的:Android volley 文件上传(二)
相关文章推荐
- Android横竖屏切换继续播放视频
- Android自动化测试技巧
- android js 互调
- android 一体化
- Android技术博文汇总
- Unable to locate Android SDK used by project
- 对Android的恶意吐槽(勿看,有毒)
- Android studio 多渠道打包
- Android 蓝牙4.0BLE开发实现对蓝牙的写入数据和读取数据
- Android开发教程
- 解决android textview自动换行问题
- Android Studio系列教程三--快捷键
- Android string-array 的使用
- 实验一 直接法解线性方程组(android)
- [Android] Service服务详解以及如何使service服务不被杀死
- Android适配总结
- Android Process 详解
- 创建一个BoundService——翻译总结自developer.android.com
- Android中Bitmap, Drawable, Byte,ID之间的转化
- android5.1 PowerManagerService和DisplayPowerControler、DisplayPowerState关系