
来源:Jude95
链接:http://www.jianshu.com/p/d9e4ddd1c530
网络请求是android客户端很重要的部分。下面从入门级开始介绍下自己Android网络请求的实践历程。希望能给刚接触Android网络部分的朋友一些帮助。
本文包含:
HTTP请求&响应
Get&Post
HttpClient & HttpURLConnection
同步&异步
HTTP缓存机制
Volley&OkHttp
Retrofit&RestAPI
网络图片加载优化
Fresco&Glide
图片管理方案
HTTP请求&响应
既然说从入门级开始就说说Http请求包的结构。
一次请求就是向目标服务器发送一串文本。什么样的文本?有下面结构的文本。
HTTP请求包结构

请求包
例子:
POST /meme.php/home/user/login HTTP/1.1
Host:114.215.86.90
Cache-Control:no-cache
Postman-Token:bd243d6b-da03-902f-0a2c-8e9377f6f6ed
Content-Type:application/x-www-form-urlencoded
tel=13637829200&password=123456
请求了就会收到响应包(如果对面存在HTTP服务器)
HTTP响应包结构

响应包
例子:
HTTP/1.1200OK
Date:Sat,02Jan201613:20:55GMT
Server:Apache/2.4.6(CentOS)PHP/5.6.14
X-Powered-By:PHP/5.6.14
Content-Length:78
Keep-Alive:timeout=5,max=100
Connection:Keep-Alive
Content-Type:application/json;charset=utf-8
{"status":202,"info":"\u6b64\u7528\u6237\u4e0d\u5b58\u5728\uff01","data":null}
Http请求方式有
方法描述
GET 请求指定url的数据,请求体为空(例如打开网页)。
POST 请求指定url的数据,同时传递参数(在请求体中)。
HEAD 类似于get请求,只不过返回的响应体为空,用于获取响应头。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。
常用只有Post与Get。
Get&Post
网络请求中我们常用键值对来传输参数(少部分api用json来传递,毕竟不是主流)。
通过上面的介绍,可以看出虽然Post与Get本意一个是表单提交一个是请求页面,但本质并没有什么区别。下面说说参数在这2者的位置。
Get方式
在url中填写参数:
http://xxxx.xx.com/xx.php?params1=value1¶ms2=value2
甚至使用路由
http://xxxx.xx.com/xxx/value1/value2/value3
这些就是web服务器框架的事了。
Post方式
参数是经过编码放在请求体中的。编码包括x-www-form-urlencoded 与 form-data。x-www-form-urlencoded的编码方式是这样:
tel=13637829200&password=123456
form-data的编码方式是这样:
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition:form-data;name="tel"
13637829200
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition:form-data;name="password"
123456
----WebKitFormBoundary7MA4YWxkTrZu0gW
x-www-form-urlencoded的优越性就很明显了。不过x-www-form-urlencoded只能传键值对,但是form-data可以传二进制
因为url是存在于请求行中的。
所以Get与Post区别本质就是参数是放在请求行中还是放在请求体中
当然无论用哪种都能放在请求头中。一般在请求头中放一些发送端的常量。
有人说:
Get是明文,Post隐藏
移动端不是浏览器,不用https全都是明文。
Get传递数据上限XXX
胡说。有限制的是浏览器中的url长度,不是Http协议,移动端请求无影响。Http服务器部分有限制的设置一下即可。
Get中文需要编码
是真的…要注意。URLEncoder.encode(params, "gbk");
还是建议用post规范参数传递方式。并没有什么更优秀,只是大家都这样社会更和谐。
上面说的是请求。下面说响应。
请求是键值对,但返回数据我们常用Json。
对于内存中的结构数据,肯定要用数据描述语言将对象序列化成文本,再用Http传递,接收端并从文本还原成结构数据。
对象(服务器)<–>文本(Http传输)<–>对象(移动端) 。
服务器返回的数据大部分都是复杂的结构数据,所以Json最适合。
Json解析库有很多Google的Gson,阿里的FastJson。
Gson的用法看这里。
http://www.cnblogs.com/Jude95/p/Mr_Dentist.html
HttpClient & HttpURLConnection
HttpClient早被废弃了,谁更好这种问题也只有经验落后的面试官才会问。具体原因可以看这里。
下面说说HttpURLConnection的用法。
最开始接触的就是这个。
publicclassNetUtils{
publicstaticStringpost(Stringurl,Stringcontent){
HttpURLConnection conn=null;
try{
// 创建一个URL对象
URL mURL=newURL(url);
// 调用URL的openConnection()方法,获取HttpURLConnection对象
conn=(HttpURLConnection)mURL.openConnection();
conn.setRequestMethod("POST");// 设置请求方法为post
conn.setReadTimeout(5000);// 设置读取超时为5秒
conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容
// post请求的参数
Stringdata=content;
// 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
OutputStream out=conn.getOutputStream();// 获得一个输出流,向服务器写数据
out.write(data.getBytes());
out.flush();
out.close();
intresponseCode=conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
if(responseCode==200){
InputStreamis=conn.getInputStream();
Stringresponse=getStringFromInputStream(is);
returnresponse;
}else{
thrownewNetworkErrorException("response status is "+responseCode);
}
}catch(Exceptione){
e.printStackTrace();
}finally{
if(conn!=null){
conn.disconnect();// 关闭连接
}
}
returnnull;
}
publicstaticStringget(Stringurl){
HttpURLConnection conn=null;
try{
// 利用string url构建URL对象
URL mURL=newURL(url);
conn=(HttpURLConnection)mURL.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConnectTimeout(10000);
intresponseCode=conn.getResponseCode();
if(responseCode==200){
InputStreamis=conn.getInputStream();
Stringresponse=getStringFromInputStream(is);
returnresponse;
}else{
thrownewNetworkErrorException("response status is "+responseCode);
}
}catch(Exceptione){
e.printStackTrace();
}finally{
if(conn!=null){
conn.disconnect();
}
}
returnnull;
}
privatestaticStringgetStringFromInputStream(InputStreamis)
throwsIOException{
ByteArrayOutputStream os=newByteArrayOutputStream();
// 模板代码 必须熟练
byte[]buffer=newbyte[1024];
intlen=-1;
while((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
}
is.close();
Stringstate=os.toString();// 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
os.close();
returnstate;
}
}
注意网络权限!被坑了多少次。
<uses-permission android:name="android.permission.INTERNET"/>
同步&异步
这2个概念仅存在于多线程编程中。
android中默认只有一个主线程,也叫UI线程。因为View绘制只能在这个线程内进行。
所以如果你阻塞了(某些操作使这个线程在此处运行了N秒)这个线程,这期间View绘制将不能进行,UI就会卡。所以要极力避免在UI线程进行耗时操作。
网络请求是一个典型耗时操作。
通过上面的Utils类进行网络请求只有一行代码。
NetUtils.get("http://www.baidu.com");//这行代码将执行几百毫秒。
如果你这样写
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Stringresponse=Utils.get("http://www.baidu.com");
}
就会死。。
这就是同步方式。直接耗时操作阻塞线程直到数据接收完毕然后返回。Android不允许的。
(本文字数超过限制,后续请看下一条内容)
公益传播测试知识、技能与正能量!感谢作者!分享测试生活,思考测试人生!
文章图片来自网络,如有侵权请见谅,请联系我们妥善处理。
twftesting@163.com
欢迎加入我们:
官网:www.huicewang.com
中国软件测试群: 172923163
测试编程技术交流群: 231767115
性能测试技术交流群: 385202672
咨询QQ:2657535456
公众号:慧测


