现在已经会使用Http请求了,但是请求的代码都是基本相同的,若每次都重写一遍就太差劲了,通常应该把这些通用的网络操作提取到一个公共类中,并提供一个静态的方法,当想要发起网络请求的时候,就简单的调用这个方法就可以了
- 自定义一个类,HttpUtil
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);
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()方法中开一个线程的话,
那么服务器响应的数据是无法进行返回的,所有的耗时逻辑都是在子线程中进行的,这个方法sendHttpRequest()会在服务器还没来的及响应的时候就执行结束了,就没有办法返回数据了
- 这个时候就需要使用java的回调机制,先定义一个接口,HttpCallbackListener
public interface HttpCallbackListener {
void onFinish(String response);
void onError(Exception e);
}
- onFinish()方法表示当服务器成功响应我们请求的时候调用,参数是服务器返回的数据
- onError()方法表示当进行网络操作出现错误的时候调用,参数是记录错误的详细信息
- 修改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);
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);
}
// 回调onFinish()
if (listener != null){
listener.onFinish(response.toString());
}
} catch (Exception e) {
// 回调onErroe()方法
if (listener != null){
listener.onError(e);
}
}finally {
if (connection != null){
connection.disconnect();
}
}
}
}).start();
}
}
- 首先给sendHttpRequest()方法中添加了一个HttpCallbackListener参数,并在方法的内部开启了一个线程,然后在子线程里去执行具体的操作
- 注意,子线程是没有办法通过return语句来返回数据的,因此这里将服务器响应的数据传入到HttpCallbackListener的onFinish()方法中,如果异常的话就将异常原因传入到onError()方法中
- 现在sendHttpRequest()方法接收的是两个参数,调用的时候还需要将HttpCallbackListener实例传入,如下
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String address = "http://www.baidu.com";
HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {
@Override
public void onFinish(String response) {
// 这里根据返回的内容执行具体的操作
}
@Override
public void onError(Exception e) {
// 这里对异常情况进行处理
}
});
}
}
- 当服务器响应的时候,就可以在onFinish()方法中对响应数据进行处理了,如果出现了异常就可以在onError()方法中进行处理了
- 当然了,使用上面的还有点稍微复杂,那么就是用OkHttp,在HttpUtil中加入一个sendOkHttpRequest()方法,如下:
public static void sendOkHttpRequest(String address,okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(address)
.build();
client.newCall(request).enqueue(callback);
}
- 可以看到在这个方法中sendOkHttpRequest()有一个okhttp3.Callback参数,这个就是OkHttp库中自带的一个回调接口,类似于我们刚才编写的,然后在client.newCall()方法之后没有像以前一样execute()方法,而是调用enqueue()方法,这个方法已将帮我们开好了子线程,然后会在子线程中去执行HTTP请求,并将结果回调到okhttp3.Callback当中
- 在调用这个sendOkHttpRequest()方法的时候就可以这样写
HttpUtil.sendOkHttpRequest("http://www.baidu.com", new okhttp3.Callback() {
@Override
public void onFailure(Call call, IOException e) {
//在这里对异常情况进行处理
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// 得到服务器返回的具体内容
String responseData = response.body().string();
}
});
- 这个方法比自定义的好用多了,只需少量的代码就可以完成复杂的网络操作
- 另外就是不管使用HttpURLConnection还是OkHttp,最终的回调接口都还是在子线程中运行的,因此我们不可以在这里执行任何的UI操作,除非借助runOnUiThread()方法来进行线程的转换,至于为什么这样,以后会学到的