在<<第一行代码>>一书中学习到的技巧,再此实验整合:
在编写网络应用时,我们经常会用到发送Http请求的地方,然而每次发送Http请求的代码几乎是相同的,所以通常情况下,我们将这些通用的网络操作提取到一个公共类里,并提供一个静态方法。(类似简单工厂模式)
以使用HttpURLConnection为例。
public class HttpUtils {
public static InputStream sendHttpRequest(final String address) {
HttpURLConnection connection = null;
try {
URL url = new URL(address);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setReadTimeout(5000);
connection.setDoOutput(true);
InputStream inputStream = connection.getInputStream();
//返回一个输入流
return inputStream;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null)
connection.disconnect();
}
return null;
}
}
以后每当发起一条请求就可以简单写成:
String address = "http://www.baidu.com";
//发送get请求,获取输入流
InputStream is= HttpUtils.sendHttpRequest(address);
此时会有一个问题,网络请求通常是耗时操作,而在方法中我们没有开启一个子线程进行网络操作,这样就有可能调用sendHttpRequest()方法时阻塞主线程。
而正因为耗时操作都在子线程中进行,如果我们在sendHttpRequest( )方法中开启一个子线程进行通信,那么服务器返回的数据是无法及时传递的,因为sendHttpRequest( )方法会在服务器还没来得及响应时就执行结束了,也就无法返回响应的数据了。
解决方案:采用JAVA回调机制
先自定义一个接口:
public interface HttpCallbackListener{
//当服务器成功响应的时候调用
void onFinish(String response);
//当网络操作出现错误的时候我们调用
void onError(Exception e);
}
然后修改HttpUtils中代码:
public class HttpUtils {
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.setDoInput(true);
connection.setRequestMethod("GET");
connection.setReadTimeout(5000);
connection.setDoOutput(true);
InputStream inputStream = connection.getInputStream();
if (listener!=null){
//回调onFinish()
listener.onFinish (inputStream);
}
} catch (Exception e) {
if (listener!=null){
//回调onError()
listener.onError (e);
}
} finally {
if (connection != null)
connection.disconnect();
}
}
}).start ();
}
}
即在子线程中不返回数据,而将服务器返回的数据交给传递给接口,在接口中接收流并进行操作,如果出现异常则传入到onError()方法中。
在调用时要传入两个参数了
HttpUtils.sendHttpRequest (address, new HttpCallBackListener () {
@Override
public void onFinish (InputStream inputStream) {
//对返回内容执行操作
}
@Override
public void onError (Exception e) {
//对异常进行处理
}
});
到这里,若是服务器返回数据成功,则返回数据交给调用方处理;若获取数据异常,则将错误信息交给调用方处理。
另外,onFinish( )和onError( )仍然是在子线程中运行的,因此不可以在里面执行UI操作,要使用异步消息处理机制。