Android HttpClient HttpUrlConnection用法总结
2015-12-08 21:37
751 查看
HttpClient
这个不用说了,Apache的API,但是不推荐使用了,在最新的api中甚至都把HttpClient去掉了。但是还是有必要掌握下HttpClient的用法的GET方式
//先将参数放入List,再对参数进行URL编码 List<BasicNameValuePair> params = new LinkedList<BasicNameValuePair>(); params.add(new BasicNameValuePair("param1", "中国")); params.add(new BasicNameValuePair("param2", "value2")); //对参数编码 String param = URLEncodedUtils.format(params, "UTF-8"); //baseUrl String baseUrl = "http://ubs.free4lab.com/php/method.php"; //将URL与参数拼接 HttpGet getMethod = new HttpGet(baseUrl + "?" + param); HttpClient httpClient = new DefaultHttpClient(); try { HttpResponse response = httpClient.execute(getMethod); //发起GET请求 Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //获取响应码 Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8"));//获取服务器响应内容 } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
POST方法
//和GET方式一样,先将参数放入List params = new LinkedList<BasicNameValuePair>(); params.add(new BasicNameValuePair("param1", "Post方法")); params.add(new BasicNameValuePair("param2", "第二个参数")); try { HttpPost postMethod = new HttpPost(baseUrl); postMethod.setEntity(new UrlEncodedFormEntity(params, "utf-8")); //将参数填入POST Entity中 HttpResponse response = httpClient.execute(postMethod); //执行POST方法 Log.i(TAG, "resCode = " + response.getStatusLine().getStatusCode()); //获取响应码 Log.i(TAG, "result = " + EntityUtils.toString(response.getEntity(), "utf-8")); //获取响应内容 } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }
HttpClient传递复杂的参数,比如文件 需要额外的jar包
常见问题
异常处理协议异常ClientProtocolException: 无效的cookie 很多http请求需要提供登录凭证 如果没有则协议异常
连接超时SocketTimeoutException: 无法连接到服务器比如服务器不可用 那么就连接超时
套接字超时ConnectTimeoutException: 既定时间内未收到服务器响应此时可以连接到服务器 但是未收到响应 那么套接字超时
HttpConnectionparam.setconnectiontimeout(param,5000) //连接超时时间 HttpConnectionparam.setsotimeout(param,5000) //套接字连接超时 ConnManagerParams.settimeout(param,5000) //连接管理器的超时 定义应用程序等待多久才让一个连接退出连接池的管理 比如连接池已经满了 新的连接就必须要等待了
使用try catch块来捕获
多线程问题
可以设置单例的httpclient 这样就可以共享设置的连接参数,但是单例的话 多线程就会有问题
HttpClient httpClient = new DefaultHttpClient(); 有多线程问题
比如两个线程都调用httpClient.execute(getMethod); getMethod使用的是同一个HttpGet对象 那么毫无疑问多线程问题
HttpConnectionparam.setconnectiontimeout(params,5000) HttpConnectionparam.setsotimeout(params,5000) ConnManagerParams.settimeout(params,5000) HttpClient httpClient = new DefaultHttpClient(ThreadSafeClientManager conMgr,HttpParams params);
ThreadSafeClientManager负责管理所有的httpclient的http连接 内部实现不会有多线程问题
此时的HttpParams作用在HttpClient上,所以可以供所有的HttpGet HttpPost对像共享
如果要定义自己的连接参数 那么可以
HttpGet getMethod = new HttpGet(baseUrl + "?" + param); HttpParams params= getMethod.getarams(); HttpConnectionparam.setconnectiontimeout(param,5000); getMethod.setparams(params);
此时的HttpParams作用在HttpGet上,不会影响到HttpClient共享的连接参数
AndroidHttpClient
HttpClient子类 适用于android开发人员连接超时/套接字超时默认20s
默认是线程安全的ThreadSafeClientManager
HttpUrlConnection
HttpUrlConnection属于Java的标准类库更轻量了 推荐使用这个 4.4开始底层通过Okhttp来实现
HttpURLConnection的多线程问题? 因为采取Okhttp的底层实现,是木有多线程的问题的,具体是为什么,需要研究
HttpURLConnection使用
1. HttpURLConnection连接URL1)创建一个URL对象
URL url = new URL(http://www.baidu.com);
2)利用HttpURLConnection对象从网络中获取网页数据
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
3)设置连接超时
conn.setConnectTimeout(6*1000);
4)对响应码进行判断
if (conn.getResponseCode() != 200) //从Internet获取网页,发送请求,将网页以流的形式读回来
throw new RuntimeException(“请求url失败”);
5)得到网络返回的输入流
InputStream is = conn.getInputStream();
6)String result = readData(is, “GBK”); //文件流输入出文件用outStream.write
7)conn.disconnect();
总结:
- 记得设置连接超时,如果网络不好,Android系统在超过默认时间会收回资源中断操作.
- 返回的响应码200,是成功.
- 在Android中对文件流的操作和JAVA SE上面是一样的.
- 在对大文件的操作时,要将文件写到SDCard上面,不要直接写到手机内存上.
- 操作大文件是,要一遍从网络上读,一遍要往SDCard上面写,减少手机内存的使用.
- 对文件流操作完,要记得及时关闭.
2. 向Internet发送请求参数
步骤:
1)创建URL对象:URL realUrl = new URL(requestUrl);
2)通过HttpURLConnection对象,向网络地址发送请求
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
3)设置容许输出:conn.setDoOutput(true);
4)设置不使用缓存:conn.setUseCaches(false);
5)设置使用POST的方式发送:conn.setRequestMethod(“POST”);
6)设置维持长连接:conn.setRequestProperty(“Connection”, “Keep-Alive”);
7)设置文件字符集:conn.setRequestProperty(“Charset”, “UTF-8”);
8)设置文件长度:conn.setRequestProperty(“Content-Length”, String.valueOf(data.length));
9)设置文件类型:conn.setRequestProperty(“Content-Type”,”application/x-www-form-urlencoded”);
10)以流的方式输出.
总结:
- 发送POST请求必须设置允许输出
- 不要使用缓存,容易出现问题.
- 在开始用HttpURLConnection对象的setRequestProperty()设置,就是生成HTML文件头.
3. 向Internet发送xml数据
XML格式是通信的标准语言,Android系统也可以通过发送XML文件传输数据.
1)将生成的XML文件写入到byte数组中,并设置为UTF-8:byte[] xmlbyte = xml.toString().getBytes(“UTF-8”);
2)创建URL对象,并指定地址和参数:URL url = new URL(http://localhost:8080/itcast/contanctmanage.do?method=readxml);
3)获得链接:HttpURLConnection conn = (HttpURLConnection) url.openConnection();
4)设置连接超时:conn.setConnectTimeout(6* 1000);
5)设置允许输出conn.setDoOutput(true);
6)设置不使用缓存:conn.setUseCaches(false);
7)设置以POST方式传输:conn.setRequestMethod(“POST”);
8)维持长连接:conn.setRequestProperty(“Connection”, “Keep-Alive”);
9)设置字符集:conn.setRequestProperty(“Charset”, “UTF-8”);
10)设置文件的总长度:conn.setRequestProperty(“Content-Length”, String.valueOf(xmlbyte.length));
11)设置文件类型:conn.setRequestProperty(“Content-Type”, “text/xml; charset=UTF-8”);
12)以文件流的方式发送xml数据:outStream.write(xmlbyte);
总结:
- 我们使用的是用HTML的方式传输文件,这个方式只能传输一般在5M一下的文件.
- 传输大文件不适合用HTML的方式,传输大文件我们要面向Socket编程.确保程序的稳定性
- 将地址和参数存到byte数组中:byte[] data = params.toString().getBytes();
HttpClient还是HttpUrlConnection
参考 Android访问网络,使用HttpURLConnection还是HttpClient?在Android 2.2版本之前,HttpClient拥有较少的bug,因此使用它是最好的选择。
而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择。它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。对于新的应用程序应该更加偏向于使用HttpURLConnection,因为在以后的工作当中我们也会将更多的时间放在优化HttpURLConnection上面。
其实现在嘛,两者都不用,就用
Okhttp
HttpUrlConnection现在的底层实现就是通过Okhttp
HttpURLConnection java的标准类(java.net),什么都没封装,用起来太原始,不方便
HttpClient Apache开源框架,提供对HTTP协议访问的封装,包括http的请求头,参数,内容体,响应等及多线程的应用。
HttpClient方便,但是封装了太多,也可能导致网络请求速度变慢,灵活度不够
HttpClient就是一个增强版的HttpURLConnection ,HttpURLConnection可以做的事情 HttpClient全部可以做;HttpURLConnection没有提供的有些功能,HttpClient也提供了
Volley中两者的使用
我们知道Volley中api<=9使用的是HttpClientStack,内部使用HttpClient。api>9使用的是HurlStack,内部使用HttpUrlConnection先来看HttpClientStack,使用起来很简单
private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) { for (String key : headers.keySet()) { httpRequest.setHeader(key, headers.get(key)); } } @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); addHeaders(httpRequest, additionalHeaders); //缓存中的头 addHeaders(httpRequest, request.getHeaders()); //request中的设置的头 onPrepareRequest(httpRequest); HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // TODO: Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); return mClient.execute(httpRequest); //调用HttpClient的excute方法,执行网络请求,最后直接返回HttpResponse } static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { case Method.GET: return new HttpGet(request.getUrl()); case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request); //设置post请求参数 return postRequest; ........ } default: throw new IllegalStateException("Unknown request method."); } private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, Request<?> request) throws AuthFailureError { byte[] body = request.getBody(); if (body != null) { HttpEntity entity = new ByteArrayEntity(body); httpRequest.setEntity(entity); //setEntity方法设置post请求参数 } }
看吧,使用起来很方便简单,都是直接封装好了,,,下面来看HurlStack,使用起来就更负责了
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<String, String>(); map.putAll(request.getHeaders()); //取出request设置的head map.putAll(additionalHeaders); //取出缓存中的Header,如果该request前面发起过网络请求,那么就会缓存下来,同时会把http的head也缓存 ........ URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); //初始化HttpURLConnection对象 for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); //设置Http请求的head } setConnectionParametersForRequest(connection, request); // Initialize HttpResponse with data from the HttpURLConnection. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); int responseCode = connection.getResponseCode(); if (responseCode == -1) { // -1 is returned by getResponseCode() if the response code could not be retrieved. // Signal to the caller that something was wrong with the connection. throw new IOException("Could not retrieve response code from HttpUrlConnection."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); //HttpResponse需要自己创建 if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) { response.setEntity(entityFromConnection(connection)); //调用HttpResponse的setEntity方法设置相应内容 } for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { if (header.getKey() != null) { Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); //调用HttpResponse的addHeader方法添加响应头 } } return response; } private HttpURLConnection openConnection(URL url, Request<?> request) throws IOException { HttpURLConnection connection = createConnection(url); int timeoutMs = request.getTimeoutMs(); connection.setConnectTimeout(timeoutMs); //设置连接超时时间 connection.setReadTimeout(timeoutMs); connection.setUseCaches(false); //不使用缓存? connection.setDoInput(true); //允许输出 // use caller-provided custom SslSocketFactory, if any, for HTTPS if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) { ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory); } return connection; } //可以看到volley支持get,post,PUT等都支持的,符合http规范 static void setConnectionParametersForRequest(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { switch (request.getMethod()) { case Method.GET: // Not necessary to set the request method because connection defaults to GET but // being explicit here. connection.setRequestMethod("GET"); break; case Method.POST: connection.setRequestMethod("POST"); addBodyIfExists(connection, request); ........... } } private static void addBodyIfExists(HttpURLConnection connection, Request<?> request) throws IOException, AuthFailureError { byte[] body = request.getBody(); if (body != null) { connection.setDoOutput(true); connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType()); //request的getBodyContentType()方法可以设置Content-Type请求头 DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(body); //把getBody()返回的byte[]数组写入输入流, out.close(); } } private static HttpEntity entityFromConnection(HttpURLConnection connection) { BasicHttpEntity entity = new BasicHttpEntity(); InputStream inputStream; try { inputStream = connection.getInputStream(); } catch (IOException ioe) { inputStream = connection.getErrorStream(); } entity.setContent(inputStream); //把响应内容写入HttpEntity entity.setContentLength(connection.getContentLength()); entity.setContentEncoding(connection.getContentEncoding()); entity.setContentType(connection.getContentType()); return entity; }
看到两者的区别了吧?
HttpClient使用起来很简单
mClient.execute(httpRequest); 直接返回HttpResponse对象,这个对象封装了响应内容和响应头
httpRequest.setHeader(key, headers.get(key)); 给请求添加头
HttpEntity entity = new ByteArrayEntity(request.getBody()); httpRequest.setEntity(entity); //给请求添加post参数
HttpURLConnection使用麻烦多了
HttpResponse对象需要自己创建,并手动添加响应内容和响应头,这里创建的是BasicHttpResponse实现了HttpResponse接口
connection.addRequestProperty(headerName, map.get(headerName)); //设置Http请求的head
DataOutputStream out = new DataOutputStream(connection.getOutputStream()); out.write(request.getBody()); //给请求添加post参数
response.addHeader(h); //调用HttpResponse的addHeader方法添加响应头
response.setEntity(entityFromConnection(connection)); //调用HttpResponse的setEntity方法设置相应内容
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories