- 一个应用程序很可能会在许多地方都使用到网络功能,而发送 HTTP 请求的代码基本都是相同的,如果我们每次都去编写一遍发送 HTTP 请求的代码,这显然是非常差劲的做法
- 应该将这些通用的网络操作提取到一个公共的类里,并提供一个静态方法,当想要发起网络请求的时候只需简单地调用一下这个方法即可。
public class HttpUtil {
public static String sendHttpRequest(String address) {
HttpURLConnection connection = null;
try {
URL url = new URL(address);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(8000);
connection.setReadTimeout(8000);
connection.setDoInput(true);
connection.setDoOutput(true);
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);
}
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}
以后每当需要发起一条 HTTP 请求的时候就可以这样写:
String address = "http://www.baidu.com";
String response = HttpUtil.sendHttpRequest(address);
- 但是 sendHttpRequest() 方法的内部并没有开启线程,这样就有可能导致在调用 sendHttpRequest() 方法的时候使得主线程被阻塞住。
- 不能直接在 sendHttpRequest() 方法中开启一个线程来发起 HTTP 请求,因为这样,服务器响应的数据是无法进行返回的。所有的耗时逻辑都是在子线程里进行的,sendHttpRequest() 方法会在服务器还来不及响应的时候就执行结束了,也就无法返回响应的数据了。
- 需要使用 Java 的回调机制。
1. 先定义一个接口,比如将它命名成 HttpCallbackListener。
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
- onFinish() 方法表示当服务器成功响应请求的时候调用。
- onError() 表示当进行网络操作出现错误的时候调用。
2. 修改 HttpUtil 中的代码。
public class HttpUtil {
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);
connection.setDoInput(true);
connection.setDoOutput(true);
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();
}
}
- 注意子线程中是无法通过 return 语句来返回数据的。
- 因此将服务器响应的数据传入 HttpCallbackListener 的 onFinish() 方法中。
- 如果出现了异常就将异常原因传入到 onError() 方法中。
3. 现在 sendHttpRequest() 方法接收两个参数了,因此在调用它的时候还需要将 HttpCallbackListener 的实例传入。
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
// 在这里根据返回内容执行具体的逻辑
}
@Override
public void onError(Exception e) {
// 在这里对异常情况进行处理
}
});
- 需要注意的是,onFinish() 方法和** onError() 方法最终还是在子线程中运行的**,因此我们不可以在这里执行任何的 UI 操作.
- 如果需要根据返回的结果来更新 UI,则仍然要使用异步消息处理机制。