- 一個(gè)應(yīng)用程序很可能會(huì)在許多地方都使用到網(wǎng)絡(luò)功能乓诽,而發(fā)送 HTTP 請(qǐng)求的代碼基本都是相同的剖膳,如果我們每次都去編寫一遍發(fā)送 HTTP 請(qǐng)求的代碼跟束,這顯然是非常差勁的做法
- 應(yīng)該將這些通用的網(wǎng)絡(luò)操作提取到一個(gè)公共的類里,并提供一個(gè)靜態(tài)方法罩句,當(dāng)想要發(fā)起網(wǎng)絡(luò)請(qǐng)求的時(shí)候只需簡(jiǎn)單地調(diào)用一下這個(gè)方法即可谍憔。
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();
}
}
}
}
以后每當(dāng)需要發(fā)起一條 HTTP 請(qǐng)求的時(shí)候就可以這樣寫:
String address = "http://www.baidu.com";
String response = HttpUtil.sendHttpRequest(address);
- 但是 sendHttpRequest() 方法的內(nèi)部并沒有開啟線程匪蝙,這樣就有可能導(dǎo)致在調(diào)用 sendHttpRequest() 方法的時(shí)候使得主線程被阻塞住主籍。
- 不能直接在 sendHttpRequest() 方法中開啟一個(gè)線程來發(fā)起 HTTP 請(qǐng)求,因?yàn)檫@樣逛球,服務(wù)器響應(yīng)的數(shù)據(jù)是無法進(jìn)行返回的千元。所有的耗時(shí)邏輯都是在子線程里進(jìn)行的,sendHttpRequest() 方法會(huì)在服務(wù)器還來不及響應(yīng)的時(shí)候就執(zhí)行結(jié)束了颤绕,也就無法返回響應(yīng)的數(shù)據(jù)了幸海。
- 需要使用 Java 的回調(diào)機(jī)制。
1. 先定義一個(gè)接口奥务,比如將它命名成 HttpCallbackListener物独。
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
- onFinish() 方法表示當(dāng)服務(wù)器成功響應(yīng)請(qǐng)求的時(shí)候調(diào)用。
- onError() 表示當(dāng)進(jìn)行網(wǎng)絡(luò)操作出現(xiàn)錯(cuò)誤的時(shí)候調(diào)用汗洒。
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) {
// 回調(diào)onFinish()方法
listener.onFinish(response.toString());
}
} catch (Exception e) {
if (listener != null) {
// 回調(diào)onError()方法
listener.onError(e);
}
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}).start();
}
}
- 注意子線程中是無法通過 return 語句來返回?cái)?shù)據(jù)的父款。
- 因此將服務(wù)器響應(yīng)的數(shù)據(jù)傳入 HttpCallbackListener 的 onFinish() 方法中溢谤。
- 如果出現(xiàn)了異常就將異常原因傳入到 onError() 方法中。
3. 現(xiàn)在 sendHttpRequest() 方法接收兩個(gè)參數(shù)了憨攒,因此在調(diào)用它的時(shí)候還需要將 HttpCallbackListener 的實(shí)例傳入世杀。
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
// 在這里根據(jù)返回內(nèi)容執(zhí)行具體的邏輯
}
@Override
public void onError(Exception e) {
// 在這里對(duì)異常情況進(jìn)行處理
}
});
- 需要注意的是,onFinish() 方法和** onError() 方法最終還是在子線程中運(yùn)行的**肝集,因此我們不可以在這里執(zhí)行任何的 UI 操作.
- 如果需要根據(jù)返回的結(jié)果來更新 UI瞻坝,則仍然要使用異步消息處理機(jī)制。