Android HttpClient接口

来源:互联网 发布:origin pro for mac 编辑:程序博客网 时间:2024/04/25 07:56

转自【http://blog.csdn.net/liuhe688/article/details/6425225】

在Android中,除了使用java.net包下的API访问HTTP服务之外,我们还可以换一种途径去完成工作。Android SDK附带了Apache的HttpClient API。Apache HttpClient是一个完善的HTTP客户端,它提供了对HTTP协议的全面支持,可以使用HTTP GET和POST进行访问。下面我们就结合实例,介绍一下HttpClient的使用方法。

我们新建一个http项目,项目结构如图:

在这个项目中,我们不需要任何的Activity,所有的操作都在单元测试类HttpTest.java中完成。

因为使用到了单元测试,所以在这里先介绍一下如何配置Android中的单元测试。所有配置信息均在AndroidManifest.xml中完成:

[xhtml] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.       package="com.scott.http"  
  4.       android:versionCode="1"  
  5.       android:versionName="1.0">  
  6.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  7.         <!-- 配置测试要使用的类库 -->  
  8.         <uses-library android:name="android.test.runner"/>  
  9.     </application>  
  10.     <!-- 配置测试设备的主类和目标包 -->  
  11.     <instrumentation android:name="android.test.InstrumentationTestRunner"  
  12.                      android:targetPackage="com.scott.http"/>  
  13.     <!-- 访问HTTP服务所需的网络权限 -->  
  14.     <uses-permission android:name="android.permission.INTERNET"/>  
  15.     <uses-sdk android:minSdkVersion="8" />  
  16. </manifest>   

然后,我们的单元测试类需要继承android.test.AndroidTestCase类,这个类本身是继承junit.framework.TestCase,并提供了getContext()方法,用于获取Android上下文环境,这个设计非常有用,因为很多Android API都是需要Context才能完成的。

现在让我们来看一下我们的测试用例,HttpTest.java代码如下:

[java] view plaincopy
  1. package com.scot.http.test;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.InputStream;  
  5. import java.util.ArrayList;  
  6. import java.util.List;  
  7.   
  8. import junit.framework.Assert;  
  9.   
  10. import org.apache.http.HttpEntity;  
  11. import org.apache.http.HttpResponse;  
  12. import org.apache.http.HttpStatus;  
  13. import org.apache.http.NameValuePair;  
  14. import org.apache.http.client.HttpClient;  
  15. import org.apache.http.client.entity.UrlEncodedFormEntity;  
  16. import org.apache.http.client.methods.HttpGet;  
  17. import org.apache.http.client.methods.HttpPost;  
  18. import org.apache.http.entity.mime.MultipartEntity;  
  19. import org.apache.http.entity.mime.content.InputStreamBody;  
  20. import org.apache.http.entity.mime.content.StringBody;  
  21. import org.apache.http.impl.client.DefaultHttpClient;  
  22. import org.apache.http.message.BasicNameValuePair;  
  23.   
  24. import android.test.AndroidTestCase;  
  25.   
  26. public class HttpTest extends AndroidTestCase {  
  27.       
  28.     private static final String PATH = "http://192.168.1.57:8080/web";  
  29.       
  30.     public void testGet() throws Exception {  
  31.         HttpClient client = new DefaultHttpClient();  
  32.         HttpGet get = new HttpGet(PATH + "/TestServlet?id=1001&name=john&age=60");  
  33.         HttpResponse response = client.execute(get);  
  34.         if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
  35.             InputStream is = response.getEntity().getContent();  
  36.             String result = inStream2String(is);  
  37.             Assert.assertEquals(result, "GET_SUCCESS");  
  38.         }  
  39.     }  
  40.       
  41.     public void testPost() throws Exception {  
  42.         HttpClient client = new DefaultHttpClient();  
  43.         HttpPost post = new HttpPost(PATH + "/TestServlet");  
  44.         List<NameValuePair> params = new ArrayList<NameValuePair>();  
  45.         params.add(new BasicNameValuePair("id""1001"));  
  46.         params.add(new BasicNameValuePair("name""john"));  
  47.         params.add(new BasicNameValuePair("age""60"));  
  48.         HttpEntity formEntity = new UrlEncodedFormEntity(params);  
  49.         post.setEntity(formEntity);  
  50.         HttpResponse response = client.execute(post);  
  51.         if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
  52.             InputStream is = response.getEntity().getContent();  
  53.             String result = inStream2String(is);  
  54.             Assert.assertEquals(result, "POST_SUCCESS");  
  55.         }  
  56.     }  
  57.       
  58.     public void testUpload() throws Exception {  
  59.         InputStream is = getContext().getAssets().open("books.xml");  
  60.         HttpClient client = new DefaultHttpClient();  
  61.         HttpPost post = new HttpPost(PATH + "/UploadServlet");  
  62.         InputStreamBody isb = new InputStreamBody(is, "books.xml");  
  63.         MultipartEntity multipartEntity = new MultipartEntity();  
  64.         multipartEntity.addPart("file", isb);  
  65.         multipartEntity.addPart("desc"new StringBody("this is description."));  
  66.         post.setEntity(multipartEntity);  
  67.         HttpResponse response = client.execute(post);  
  68.         if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
  69.             is = response.getEntity().getContent();  
  70.             String result = inStream2String(is);  
  71.             Assert.assertEquals(result, "UPLOAD_SUCCESS");  
  72.         }  
  73.     }  
  74.       
  75.     //将输入流转换成字符串  
  76.     private String inStream2String(InputStream is) throws Exception {  
  77.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  78.         byte[] buf = new byte[1024];  
  79.         int len = -1;  
  80.         while ((len = is.read(buf)) != -1) {  
  81.             baos.write(buf, 0, len);  
  82.         }  
  83.         return new String(baos.toByteArray());  
  84.     }  
  85. }  

因为此文件包含三个测试用例,所以我将会逐个介绍一下。

首先,需要注意的是,我们定位服务器地址时使用到了IP,因为这里不能用localhost,服务端是在windows上运行,而本单元测试运行在Android平台,如果使用localhost就意味着在Android内部去访问服务,可能是访问不到的,所以必须用IP来定位服务。

我们先来分析一下testGet测试用例。我们使用了HttpGet,请求参数直接附在URL后面,然后由HttpClient执行GET请求,如果响应成功的话,取得响应内如输入流,并转换成字符串,最后判断是否为GET_SUCCESS。

testGet测试对应服务端Servlet代码如下:

[java] view plaincopy
  1. @Override  
  2.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  3.         System.out.println("doGet method is called.");  
  4.         String id = request.getParameter("id");  
  5.         String name = request.getParameter("name");  
  6.         String age = request.getParameter("age");  
  7.         System.out.println("id:" + id + ", name:" + name + ", age:" + age);  
  8.         response.getWriter().write("GET_SUCCESS");  
  9.     }  

 然后再说testPost测试用例。我们使用了HttpPost,URL后面并没有附带参数信息,参数信息被包装成一个由NameValuePair类型组成的集合的形式,然后经过UrlEncodedFormEntity处理后调用HttpPost的setEntity方法进行参数设置,最后由HttpClient执行。

testPost测试对应的服务端代码如下:

[java] view plaincopy
  1. @Override  
  2.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  3.         System.out.println("doPost method is called.");  
  4.         String id = request.getParameter("id");  
  5.         String name = request.getParameter("name");  
  6.         String age = request.getParameter("age");  
  7.         System.out.println("id:" + id + ", name:" + name + ", age:" + age);  
  8.         response.getWriter().write("POST_SUCCESS");  
  9.     }  

上面两个是最基本的GET请求和POST请求,参数都是文本数据类型,能满足普通的需求,不过在有的场合例如我们要用到上传文件的时候,就不能使用基本的GET请求和POST请求了,我们要使用多部件的POST请求。下面介绍一下如何使用多部件POST操作上传一个文件到服务端。

由于Android附带的HttpClient版本暂不支持多部件POST请求,所以我们需要用到一个HttpMime开源项目,该组件是专门处理与MIME类型有关的操作。因为HttpMime是包含在HttpComponents 项目中的,所以我们需要去apache官方网站下载HttpComponents,然后把其中的HttpMime.jar包放到项目中去,如图:

然后,我们观察testUpload测试用例,我们用HttpMime提供的InputStreamBody处理文件流参数,用StringBody处理普通文本参数,最后把所有类型参数都加入到一个MultipartEntity的实例中,并将这个multipartEntity设置为此次POST请求的参数实体,然后执行POST请求。服务端Servlet代码如下:

[java] view plaincopy
  1. package com.scott.web.servlet;  
  2.   
  3. import java.io.FileOutputStream;  
  4. import java.io.IOException;  
  5. import java.util.Iterator;  
  6. import java.util.List;  
  7.   
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.http.HttpServlet;  
  10. import javax.servlet.http.HttpServletRequest;  
  11. import javax.servlet.http.HttpServletResponse;  
  12.   
  13. import org.apache.commons.fileupload.FileItem;  
  14. import org.apache.commons.fileupload.FileItemFactory;  
  15. import org.apache.commons.fileupload.FileUploadException;  
  16. import org.apache.commons.fileupload.disk.DiskFileItemFactory;  
  17. import org.apache.commons.fileupload.servlet.ServletFileUpload;  
  18.   
  19. @SuppressWarnings("serial")  
  20. public class UploadServlet extends HttpServlet {  
  21.       
  22.     @Override  
  23.     @SuppressWarnings("rawtypes")  
  24.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
  25.         boolean isMultipart = ServletFileUpload.isMultipartContent(request);  
  26.         if (isMultipart) {  
  27.             FileItemFactory factory = new DiskFileItemFactory();  
  28.             ServletFileUpload upload = new ServletFileUpload(factory);  
  29.             try {  
  30.                 List items = upload.parseRequest(request);  
  31.                 Iterator iter = items.iterator();  
  32.                 while (iter.hasNext()) {  
  33.                     FileItem item = (FileItem) iter.next();  
  34.                     if (item.isFormField()) {  
  35.                         //普通文本信息处理  
  36.                         String paramName = item.getFieldName();  
  37.                         String paramValue = item.getString();  
  38.                         System.out.println(paramName + ":" + paramValue);  
  39.                     } else {  
  40.                         //上传文件信息处理  
  41.                         String fileName = item.getName();  
  42.                         byte[] data = item.get();  
  43.                         String filePath = getServletContext().getRealPath("/files") + "/" + fileName;  
  44.                         FileOutputStream fos = new FileOutputStream(filePath);  
  45.                         fos.write(data);  
  46.                         fos.close();  
  47.                     }  
  48.                 }  
  49.             } catch (FileUploadException e) {  
  50.                 e.printStackTrace();  
  51.             }  
  52.         }  
  53.         response.getWriter().write("UPLOAD_SUCCESS");  
  54.     }  
  55. }  

服务端使用apache开源项目FileUpload进行处理,所以我们需要commons-fileupload和commons-io这两个项目的jar包,对服务端开发不太熟悉的朋友可以到网上查找一下相关资料。

介绍完上面的三种不同的情况之后,我们需要考虑一个问题,在实际应用中,我们不能每次都新建HttpClient,而是应该只为整个应用创建一个HttpClient,并将其用于所有HTTP通信。此外,还应该注意在通过一个HttpClient同时发出多个请求时可能发生的多线程问题。针对这两个问题,我们需要改进一下我们的项目:

1.扩展系统默认的Application,并应用在项目中。

2.使用HttpClient类库提供的ThreadSafeClientManager来创建和管理HttpClient。

改进后的项目结构如图:

其中MyApplication扩展了系统的Application,代码如下:

[java] view plaincopy
  1. package com.scott.http;  
  2.   
  3. import org.apache.http.HttpVersion;  
  4. import org.apache.http.client.HttpClient;  
  5. import org.apache.http.conn.ClientConnectionManager;  
  6. import org.apache.http.conn.scheme.PlainSocketFactory;  
  7. import org.apache.http.conn.scheme.Scheme;  
  8. import org.apache.http.conn.scheme.SchemeRegistry;  
  9. import org.apache.http.conn.ssl.SSLSocketFactory;  
  10. import org.apache.http.impl.client.DefaultHttpClient;  
  11. import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;  
  12. import org.apache.http.params.BasicHttpParams;  
  13. import org.apache.http.params.HttpParams;  
  14. import org.apache.http.params.HttpProtocolParams;  
  15. import org.apache.http.protocol.HTTP;  
  16.   
  17. import android.app.Application;  
  18.   
  19. public class MyApplication extends Application {  
  20.   
  21.     private HttpClient httpClient;  
  22.       
  23.     @Override  
  24.     public void onCreate() {  
  25.         super.onCreate();  
  26.         httpClient = this.createHttpClient();  
  27.     }  
  28.       
  29.     @Override  
  30.     public void onLowMemory() {  
  31.         super.onLowMemory();  
  32.         this.shutdownHttpClient();  
  33.     }  
  34.       
  35.     @Override  
  36.     public void onTerminate() {  
  37.         super.onTerminate();  
  38.         this.shutdownHttpClient();  
  39.     }  
  40.       
  41.     //创建HttpClient实例  
  42.     private HttpClient createHttpClient() {  
  43.         HttpParams params = new BasicHttpParams();  
  44.         HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);  
  45.         HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);  
  46.         HttpProtocolParams.setUseExpectContinue(params, true);  
  47.           
  48.         SchemeRegistry schReg = new SchemeRegistry();  
  49.         schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));  
  50.         schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));  
  51.           
  52.         ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);  
  53.           
  54.         return new DefaultHttpClient(connMgr, params);  
  55.     }  
  56.       
  57.     //关闭连接管理器并释放资源  
  58.     private void shutdownHttpClient() {  
  59.         if (httpClient != null && httpClient.getConnectionManager() != null) {  
  60.             httpClient.getConnectionManager().shutdown();  
  61.         }  
  62.     }  
  63.       
  64.     //对外提供HttpClient实例  
  65.     public HttpClient getHttpClient() {  
  66.         return httpClient;  
  67.     }  
  68. }  

我们重写了onCreate()方法,在系统启动时就创建一个HttpClient;重写了onLowMemory()和onTerminate()方法,在内存不足和应用结束时关闭连接,释放资源。需要注意的是,当实例化DefaultHttpClient时,传入一个由ThreadSafeClientConnManager创建的一个ClientConnectionManager实例,负责管理HttpClient的HTTP连接。

然后,想要让我们这个加强版的“Application”生效,需要在AndroidManifest.xml中做如下配置:

[c-sharp] view plaincopy
  1. <application  android:name=".MyApplication" ...>  
  2. ...  
  3. </application>  

如果我们没有配置,系统默认会使用android.app.Application,我们添加了配置,系统就会使用我们的com.scott.http.MyApplication,然后就可以在context中调用getApplication()来获取MyApplication实例。

有了上面的配置,我们就可以在活动中应用了,HttpActivity.java代码如下:

[c-sharp] view plaincopy
  1. package com.scott.http;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.InputStream;  
  5.   
  6. import org.apache.http.HttpResponse;  
  7. import org.apache.http.HttpStatus;  
  8. import org.apache.http.client.HttpClient;  
  9. import org.apache.http.client.methods.HttpGet;  
  10.   
  11. import android.app.Activity;  
  12. import android.os.Bundle;  
  13. import android.view.View;  
  14. import android.widget.Button;  
  15. import android.widget.Toast;  
  16.   
  17. public class HttpActivity extends Activity {  
  18.     @Override  
  19.     protected void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.main);  
  22.         Button btn = (Button) findViewById(R.id.btn);  
  23.         btn.setOnClickListener(new View.OnClickListener() {  
  24.             @Override  
  25.             public void onClick(View v) {  
  26.                 execute();  
  27.             }  
  28.         });  
  29.           
  30.     }  
  31.       
  32.     private void execute() {  
  33.         try {  
  34.             MyApplication app = (MyApplication) this.getApplication();  //获取MyApplication实例  
  35.             HttpClient client = app.getHttpClient();    //获取HttpClient实例  
  36.             HttpGet get = new HttpGet("http://192.168.1.57:8080/web/TestServlet?id=1001&name=john&age=60");  
  37.             HttpResponse response = client.execute(get);  
  38.             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
  39.                 InputStream is = response.getEntity().getContent();  
  40.                 String result = inStream2String(is);  
  41.                 Toast.makeText(this, result, Toast.LENGTH_LONG).show();  
  42.             }  
  43.         } catch (Exception e) {  
  44.             e.printStackTrace();  
  45.         }  
  46.     }  
  47.       
  48.     //将输入流转换成字符串  
  49.     private String inStream2String(InputStream is) throws Exception {  
  50.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  51.         byte[] buf = new byte[1024];  
  52.         int len = -1;  
  53.         while ((len = is.read(buf)) != -1) {  
  54.             baos.write(buf, 0, len);  
  55.         }  
  56.         return new String(baos.toByteArray());  
  57.     }  
  58. }  

点击“execute”按钮,执行结果如下:

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为手机音量低怎么办 手机电池冲鼓了怎么办 手机电池起鼓了怎么办 手机信息总提示怎么办 一体机电池不耐用怎么办 血糖偏高怎么办雅培益力佳SR 投诉电话打不通怎么办 宝宝换奶粉拉肚子怎么办 微店没有客源怎么办 itunes文件被保护怎么办 魅族e1黑屏了怎么办 窗帘打孔的扣环怎么办 棉质裤子掉色怎么办 孕期喝咖啡了怎么办 实体店买到假手机怎么办 派派提现没有那么多好友怎么办 派派提现没有支付宝怎么办 电脑电源不够用怎么办 电脑电源不够会怎么办 中行信用卡异常了怎么办 美借还款后秒拒怎么办 海尔空调关不了怎么办 华为p9无服务怎么办 贝贝买到假货怎么办 京东不予退货怎么办? 咸鱼收到货不对怎么办 闲鱼没收到货怎么办 淘宝购物不到货怎么办 百世快递不派送怎么办 圆通快递不派送怎么办 无卡存款没到账怎么办 中国银行分行冻结信用卡怎么办 银行信用卡没还怎么办 免税店提货单丢了怎么办 店长故意整我怎么办 被康妆大道骗了怎么办 银座卡丢了怎么办 银座消费卡丢失怎么办 天津欠债不还怎么办 苹果x买到假的怎么办 网贷到我们家要钱怎么办?