大多数Android的app都会使用HTTP协议来发送和接收数据。在Android开发中,一般使用两种http客户端:一个是Apache的HttpClient,另外一个是HttpURLConnection。这两种HTTP客户端API都支持HTTPS协议,流数据上传和下载,配置超时,IPV6协议以及链接池等等。android
HttpClient的API众多,而且bug少比较稳定。可是,HttpClient的API比较大,很难在保证兼容性的前提下去对其进行扩展。因此不少Android团队并不太喜欢使用它。HttpClient是一个接口,里面封装了须要执行的http请求,身份验证,链接管理等等,有三个主要的实现类:AbstractHttpClient, AndroidHttpClient, DefaultHttpClient。下面咱们来看一下AndroidHttpClient,它对DefaultHttpClient进行了改进使之更适合于Android开发。因而,AndroidHttpClient进行请求发送和响应接收步骤以下:服务器
一般状况下,咱们并不在主线程中进行网络请求操做,而是新开一个子线程来进行网络操做,下面的代码展现了如何利用AndroidHttpClient完成网络登陆验证的任务:网络
public class LoginTask implements Runnable { private String username; private String password; public LoginTask(String username, String password) { // 初始化用户名和密码 this.username = username; this.password = password; } @Override public void run() { // 设置访问的Web站点 String path = "http://xxxx/loginas.aspx"; //设置Http请求参数 Map<String, String> params = new HashMap<String, String>(); params.put("username", username); params.put("password", password); String result = sendHttpClientPost(path, params, "utf-8"); //把返回的接口输出 System.out.println(result); } /** * 发送Http请求到Web站点 * @param path Web站点请求地址 * @param map Http请求参数 * @param encode 编码格式 * @return Web站点响应的字符串 */ private String sendHttpClientPost(String path,Map<String, String> map,String encode) { List<NameValuePair> list=new ArrayList<NameValuePair>(); if(map!=null&&!map.isEmpty()) { for(Map.Entry<String, String> entry:map.entrySet()) { //解析Map传递的参数,使用一个键值对对象BasicNameValuePair保存。 list.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } } try { //实现将请求 的参数封装封装到HttpEntity中。 UrlEncodedFormEntity entity=new UrlEncodedFormEntity(list, encode); //使用HttpPost请求方式 HttpPost httpPost=new HttpPost(path); //设置请求参数到Form中。 httpPost.setEntity(entity); //实例化一个默认的Http客户端,使用的是AndroidHttpClient HttpClient client=AndroidHttpClient.newInstance(""); //执行请求,并得到响应数据 HttpResponse httpResponse= client.execute(httpPost); //判断是否请求成功,为200时表示成功,其余均问有问题。 if(httpResponse.getStatusLine().getStatusCode()==200) { //经过HttpEntity得到响应流 InputStream inputStream=httpResponse.getEntity().getContent(); return changeInputStream(inputStream,encode); } } 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(); } return ""; } /** * 把Web站点返回的响应流转换为字符串格式 * @param inputStream 响应流 * @param encode 编码格式 * @return 转换后的字符串 */ private String changeInputStream(InputStream inputStream, String encode) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; String result=""; if (inputStream != null) { try { while ((len = inputStream.read(data)) != -1) { outputStream.write(data,0,len); } result=new String(outputStream.toByteArray(),encode); } catch (IOException e) { e.printStackTrace(); } } return result; } }
相比之下,HttpURLConnection就显得更通用一些。它是一款多用途,轻量级的HTTP客户端,适用于大多数的app客户端。同时,HttpURLConnection简单,便于扩展。可是坑爹的是,在Android2.2以前,HttpURLConnection有一些bug,例如在试图关闭InputStream的时候会致使链接池失效。因此,推荐在2.3以后的版本中使用HttpURLConnection。app
下面以请求百度首页的logo为例子,演示使用HttpURLConnection的GET方法完成网络请求的任务:async
public class getImageTask{ private static String URL_PATH = http://www.baidu.com/img/bd_logo1.png; /** * @param args */ public static void main(String[] args) { // 调用方法获取图片并保存 saveImageToDisk(); } /** * 经过URL_PATH的地址访问图片并保存到本地 */ public static void saveImageToDisk() { InputStream inputStream= getInputStream(); byte[] data=new byte[1024]; int len=0; FileOutputStream fileOutputStream=null; try { //把图片文件保存在本地F盘下 fileOutputStream=new FileOutputStream("F:\\test.png"); while((len=inputStream.read(data))!=-1) { //向本地文件中写入图片流 fileOutputStream.write(data,0,len); } } catch (IOException e) { e.printStackTrace(); } finally { //最后关闭流 if(inputStream!=null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(fileOutputStream!=null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 经过URL获取图片 * @return URL地址图片的输入流。 */ public static InputStream getInputStream() { InputStream inputStream = null; HttpURLConnection httpURLConnection = null; try { //根据URL地址实例化一个URL对象,用于建立HttpURLConnection对象。 URL url = new URL(URL_PATH); if (url != null) { //openConnection得到当前URL的链接 httpURLConnection = (HttpURLConnection) url.openConnection(); //设置3秒的响应超时 httpURLConnection.setConnectTimeout(3000); //设置容许输入 httpURLConnection.setDoInput(true); //设置为GET方式请求数据 httpURLConnection.setRequestMethod("GET"); //获取链接响应码,200为成功,若是为其余,均表示有问题 int responseCode=httpURLConnection.getResponseCode(); if(responseCode==200) { //getInputStream获取服务端返回的数据流。 inputStream=httpURLConnection.getInputStream(); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return inputStream; } }
若是使用POST方法,则须要设置请求参数。下面咱们使用POST方式,利用HttpURLConnection完成和上面同样的登陆验证功能:ide
public class LoginTask implements Runnable{ private static String PATH = "http://xxxxx/loginas.aspx"; private static URL url; private String username;
private String password;
public LoginTask(String username, String password) {
// 初始化用户名和密码
this.username = username;
this.password = password;
} /** * 经过给定的请求参数和编码格式,获取服务器返回的数据 * @param params 请求参数 * @param encode 编码格式 * @return 得到的字符串 */ public static String sendPostMessage(Map<String, String> params, String encode) { StringBuffer buffer = new StringBuffer(); if (params != null && !params.isEmpty()) { for (Map.Entry<String, String> entry : params.entrySet()) { try { buffer.append(entry.getKey()) .append("=") .append(URLEncoder.encode(entry.getValue(), encode)) .append("&");//请求的参数之间使用&分割。 } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } buffer.deleteCharAt(buffer.length() - 1); System.out.println(buffer.toString()); try { HttpURLConnection urlConnection = (HttpURLConnection) url .openConnection(); urlConnection.setConnectTimeout(3000); //设置容许输入输出 urlConnection.setDoInput(true); urlConnection.setDoOutput(true); byte[] mydata = buffer.toString().getBytes(); //设置请求报文头,设定请求数据类型 urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); //设置请求数据长度 urlConnection.setRequestProperty("Content-Length", String.valueOf(mydata.length)); //设置POST方式请求数据 urlConnection.setRequestMethod("POST"); OutputStream outputStream = urlConnection.getOutputStream(); outputStream.write(mydata); int responseCode = urlConnection.getResponseCode(); if (responseCode == 200) { return changeInputStream(urlConnection.getInputStream(), encode); } } catch (IOException e) { e.printStackTrace(); } } return ""; } /** * 把服务端返回的输入流转换成字符串格式 * @param inputStream 服务器返回的输入流 * @param encode 编码格式 * @return 解析后的字符串 */ private static String changeInputStream(InputStream inputStream, String encode) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; String result=""; if (inputStream != null) { try { while ((len = inputStream.read(data)) != -1) { outputStream.write(data,0,len); } result=new String(outputStream.toByteArray(),encode); } catch (IOException e) { e.printStackTrace(); } } return result; } @Override public void run() { //经过Map设置请求字符串。
try {
url = new URL(PATH);
} catch (Exception e) {
e.printStackTrace();
}
Map<String, String> params = new HashMap<String, String>(); params.put("username", "admin"); params.put("password", "123"); String result=sendPostMessage(params, "utf-8"); System.out.println(result); } }
那么哪一个客户端更好些呢?在2.2以前使用httpClient能够避免一些bug。而在2.3以后的版本中使用HttpURLConnection是最好的选择,简单的API适合于Android开发。透明压缩和应答数据的捕获,减小了网络的使用,提高了性能而且减小了电池的消耗。性能
在随后咱们介绍的开源库中,volley在2.3以前的版本中使用了HttpClient,而在2.3以后使用了HttpURLConnection;android-async-http中封装了HttpClient。this