您的位置:首页 > 理论基础 > 计算机网络

android 网络编程 - HttpURLConnection与HttpClient

2017-03-15 17:05 423 查看
安卓和Java应用开发少不了要提交HTTP请求,而基本上目前有两个实现方式:HttpUrlConnection(即URL.openConnection)和HttpClient。 HttpClient是apache的开源实现,而HttpUrlConnection是安卓标准实现。

1. HttpURLConnection

Android 2.2版本之前,HttpURLConnection一直存在着一些令人厌烦的bug。比如说对一个可读的InputStream调用close()方法时,就有可能会导致连接池失效了。那么我们通常的解决办法就是直接禁用掉连接池的功能。所以在Android 2.2版本以及之前的版本使用HttpClient是较好的选择,而在Android 2.3版本及以后,HttpURLConnection则是最佳的选择,它的API简单,体积较小,因而非常适用于Android项目。压缩和缓存机制可以有效地减少网络访问的流量,在提升速度和省电方面也起到了较大的作用。另外在Android 6.0版本中,HttpClient库被移除了。

1.1 Get

首先需要获取到 HttpURLConnection 的实例,一般只需 new 出一个 URL 对象,并传入 目标的网络地址,然后调用一下 openConnection()方法即可。得到了 HttpURLConnection 的实例之后,我们可以设置一下 HTTP 请求所使用的方法。 常用的方法主要有两个,GET 和 POST。GET 表示希望从服务器那里获取数据,而 POST 则 表示希望提交数据给服务器。接下来就可以进行一些自由的定制了,比如设置连接超时、读取超时的毫秒数,以及服 务器希望得到的一些消息头等。这部分内容根据自己的实际情况进行编写。之后再调用 getInputStream()方法就可以获取到服务器返回的输入流了,剩下的任务就是 对输入流进行读取。接着利用 BufferedReader 对服务器 返回的流进行读取,并将结果存放到了一个 Message 对象中。这里为什么要使用 Message 对 象呢?当然是因为子线程中无法对 UI 进行操作了。我们希望可以将服务器返回的内容显示 到界面上,所以就创建了一个 Message 对象,并使用 Handler 将它发送出去。之后又在 Handler 的 handleMessage()方法中对这条 Message 进行处理。最后可以调用 disconnect()方法将这个 HTTP 连接关闭掉。

private void connectWithHttpURLConnection() {
new Thread( new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;
try {
// 调用URL对象的openConnection方法获取HttpURLConnection的实例
URL url = new URL("http://www.cnblogs.com/gzdaijie");
connection = (HttpURLConnection) url.openConnection();
// 设置请求方式,GET或POST
connection.setRequestMethod("GET");
// 设置连接超时、读取超时的时间,单位为毫秒(ms)
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
// getInputStream方法获取服务器返回的输入流
InputStream in = connection.getInputStream();
// 使用BufferedReader对象读取返回的数据流
// 按行读取,存储在StringBuider对象response中
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
Message message = new Message();
message.what = SHOW_RESPONSE;
// 将服务器返回的结果存放到Message中
message.obj = response.toString();
handler.sendMessage(message);
} catch (Exception e){
e.printStackTrace();
} finally {
if (connection != null){
// 结束后,关闭连接
connection.disconnect();
}
}
}
}).start();
}


1.2 Post

注意需要对中文进行设置编码格式

URLEncoder.encode(nickname.getText().toString(), “utf-8”)

public void send() {
String target = "http://192.168.1.66:8081/blog/dealPost.jsp";   //要提交的目标地址
URL url;
try {
url = new URL(target);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); // 创建一个HTTP连接
urlConn.setRequestMethod("POST"); // 指定使用POST请求方式
urlConn.setDoInput(true); // 向连接中写入数据
urlConn.setDoOutput(true); // 从连接中读取数据
urlConn.setUseCaches(false); // 禁止缓存
urlConn.setInstanceFollowRedirects(true);   //自动执行HTTP重定向

DataOutputStream out = new DataOutputStream(urlConn.getOutputStream()); // 获取输出流
String param = "nickname="
+ URLEncoder.encode(nickname.getText().toString(), "utf-8")
+ "&content="
+ URLEncoder.encode(content.getText().toString(), "utf-8"); //连接要提交的数据
out.writeBytes(param);//将要传递的数据写入数据输出流
out.flush();    //输出缓存
out.close();    //关闭数据输出流
// 判断是否响应成功
if (urlConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
InputStreamReader in = new InputStreamReader(urlConn.getInputStream()); // 获得读取的内容
BufferedReader buffer = new BufferedReader(in); // 获取输入流对象
String inputLine = null;
while ((inputLine = buffer.readLine()) != null) {
result += inputLine + "\n";
}
in.close(); //关闭字符输入流
}
urlConn.disconnect();   //断开连接
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}


2. HttpClient

HttpClient是Apache提供的库,提供了高效的、最新的支持HTTP协议的工具包,封装了众多的http请求、响应等方法,但有个缺点就是太重量级了,API太多了。

2.1 Get

首先你需要知道,HttpClient 是一个接口,因此无法创建它的实例,通常情况下都会创 建一个 DefaultHttpClient 的实例。接下来如果想要发起一条 GET 请求,就可以创建一个 HttpGet 对象,并传入目标的网络 地址,然后调用 HttpClient 的 execute()方法即可。执行 execute()方法之后会返回一个 HttpResponse 对象,服务器所返回的所有信息就会包 含在这里面。通常情况下我们都会先取出服务器返回的状态码,如果等于 200 就说明请求和响应都成功了。接下来在这个 if 判断的内部取出服务返回的具体内容,可以调用 getEntity()方法获取到 一个 HttpEntity 实例,然后再用 EntityUtils.toString()这个静态方法将 HttpEntity 转换成字符串 即可。注意如果服务器返回的数据是带有中文的,直接调用 EntityUtils.toString()方法进行转换 会有乱码的情况出现,这个时候只需要在转换的时候将字符集指定成 utf-8 就可以了。

// 创建DefaultHttpClient实例
HttpClient httpClient = new DefaultHttpClient();
//传入网址,然后执行
HttpGet httpGet = new HttpGet("http://www.cnblogs.com/gzdaijie");
HttpResponse httpResponse = httpClient.execute(httpGet);
// 由状态码判断请求结果,
// 常见状态码 200 请求成功,404 页面未找到,关于HTTP的更多状态码直接GOOGLE
if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
// 请求成功,使用HttpEntity获得返回数据
// 使用EntityUtils将返回数据转换为字符串
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity);
//如果是中文,指定编码
//==>String response = EntityUtils.toString(entity, "utf-8");

//或者生成一个BufferedReader
BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
}


2.2 Post

HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost("http://www.cnblogs.com/gzdaijie");
// 使用NameValuePair(键值对)存放参数
List<NameValuePair> data = new ArrayList<NameValuePair>();
// 添加键值对
data.add(new BasicNameValuePair("stu_no", 12345));
data.add(new BasicNameValuePair("stu_name", "Tom"));
// 使用setEntity方法传入编码后的参数
httpPost.setEntity(new UrlEncodedFormEntity(data, "utf-8"));
// 执行该POST请求
HttpResponse httpResponse = httpClient.execute(httpPost);
// .....省略处理httpResponse的代码,与GET方式一致


3. 用回调函数实现网络编程

3.1 定义接口HttpCallbackListener,为了实现回调

在接口中定义了两个方法,onFinish()方法表示当服务器成功响应我们请 求的时候调用,onError()表示当进行网络操作出现错误的时候调用。这两个方法都带有参数, onFinish()方法中的参数代表着服务器返回的数据,而 onError()方法中的参数记录着错误的 详细信息。

// 定义HttpCallbackListener接口
// 包含两个方法,成功和失败的回调函数定义
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}


3.2 定义类HttpUtil,为了网络助手类

先给 sendHttpRequest()方法添加了一个 HttpCallbackListener 参数,并在方法的内 部开启了一个子线程,然后在子线程里去执行具体的网络操作。注意子线程中是无法通过 return 语句来返回数据的,因此这里我们将服务器响应的数据传入了 HttpCallbackListener 的 onFinish()方法中,如果出现了异常就将异常原因传入到 onError()方法中。

/* 创建一个新的类 HttpTool,将公共的操作抽象出来
* 为了避免调用sendHttpRequest方法时需实例化,设置为静态方法
* 传入HttpCallbackListener对象为了方法回调
* 因为网络请求比较耗时,一般在子线程中进行,
* 为了获得服务器返回的数据,需要使用java的回调机制 */

public class HttpTool {
public static void sendHttpRequest(final String address, final HttpCallbackListener listener) {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection connection = null;

try {
URL url = new URL(address);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
if (listener != null) {
// 回调方法 onFinish()
listener.onFinish(response.toString());
}
} catch (Exception e) {
if (listener != null) {
// 回调方法 onError()
listener.onError(e);
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
}


3.3 调用网络助手类

这样的话,当服务器成功响应的时候我们就可以在 onFinish()方法里对响应数据进行处 理了,类似地,如果出现了异常,就可以在 onError()方法里对异常情况进行处理。如此一来, 我们就巧妙地利用回调机制将响应数据成功返回给调用方了。

另外需要注意的是,onFinish()方法和 onError()方法最终还是在子线程中运行的,因此 我们不可以在这里执行任何的 UI 操作,如果需要根据返回的结果来更新 UI,则仍然要使用异步消息处理机制(Handler)。

//使用该HttpTool发起GET请求
String url = "http://www.cnblogs.com/gzdaijie";
HttpTool.sendHttpRequest(url,new HttpCallbackListener(){
@Override
public void onFinish(String response) {
// ...省略对返回结果的处理代码
}

@Override
public void onError(Exception e) {
// ...省略请求失败的处理代码
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息