Android开发中给服务器发送Http请求获取响应

来源:互联网 发布:vue vendor.js 编辑:程序博客网 时间:2024/06/03 15:57

在android中,有很多的情况都要用到网络的功能,而发送HTTP请求的代码基本上是一样的。所以我觉得很有必要将这些通用的操作提取到一个公共类里,并提供一个静态的方法,当想要发起网络请求的时候只需要简单的调用一下这个方法即可。发送HTTP请求的方式在安卓开发中一般有两种,HttpURLConnection和HttpClient。在这里采用HttpURLConnection的写法:

public class HttpUtil {public static String sendHttpRequest(String address) {private HttpURLConnection connection;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 builder = new StringBuilder();String line;while ((line = reader.readLine()) != null) {builder.append(line);// 一行行的读取内容并追加到builder中去}return builder.toString();} catch (Exception e) {e.printStackTrace();return e.getMessage();} finally {if (connection != null) {connection.disconnect();//连接不为空就关闭连接}}}}


以后每当发起一条HTTP请求的时候就可以这样写:

String address = "https://www.baidu.com";String response = HttpUtil.sendHttpRequest(address);
在获取到服务器的响应数据后我们就可以对它进行解析和处理了。但是需要注意的是网络操作属于耗时的操作,而sendHttpRequest()方法的内部并没有开启线程,这样就有可能导致在调用sendHttpRequest()方法的时候使得主线程被阻塞。

为什么可能会导致主线程阻塞呢?

这是因为在主线程中执行了耗时操作,如果耗时过久,就会使应用程序出现ANR异常,如果不知道这个异常的话自己百度一下就好了。一般主线程中用户的输入事件操作超过5s就会出现上述的异常,所以发送请求从服务器上获取数据是可能会导致主线程阻塞的。

你这时可能会说,很简单,在sendHttpRequest()方法内部开启一个线程不就解决这个问题了吗?其实不是你想的那么简单,如果我们在sendHttpRequest()方法中开启了一个线程来发HTTP请求,那么服务器响应的数据是无法进行返回的,所有的耗时操作逻辑都是在子线程里进行的,sendHttpRequest()方法会在服务器没来得及响应的时候就执行结束了,当然也就无法返回响应的数据了。

为什么会没响应就执行结束呢?

那是因为线程是并发的。懂了吗?不懂得话自己百度一下。

那么遇到上面说的"服务器没来得及响应的时候就执行结束了"这一情况,我们就要使用Java的回调机制了。下面来学习一下回调机制到底是如何使用的。

首先需要定义一个接口,比如将它命名为HttpCallbackListener,代码如下:

/** * 定义一个接口,接口中定义了两个方法 * @author Administrator * */public interface HttpCallbackListener {void onFinish(String response);//当服务器成功响应的时候会调用该方法void onError(Exception e);//当进行网络操作错误的时候会调用该方法}
可以看到,我们在接口中定义了两个方法,onFinish()方法表示当服务器成功响应我们请求的时候调用,onError()表示进行网络操作出现错误的时候调用,而onError()方法中的参数记录着错误的详细信息。

接着修改HttpUtil中的代码,如下:

package com.example.android_ydhl_system.util;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.net.HttpURLConnection;import java.net.URL;public class HttpUtil {/** * 发送网络请求的时候调用该方法 * @param address URL对象 * @param listener实例化的接口对象,回调方法需要实例化接口 */public static void sendHttpRequest(final String address,final HttpCallbackListener listener) {new Thread() {private HttpURLConnection connection;public void run() {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 builder = new StringBuilder();// 创建一个StringBuilder对象String line;while ((line = reader.readLine()) != null) {builder.append(line);// 一行行的读取内容并追加到builder中去}if (listener != null) {// 回调onFinish()方法listener.onFinish(builder.toString());}} catch (Exception e) {e.printStackTrace();// 回调onError()方法listener.onError(e);} finally {if (connection != null) {connection.disconnect();//连接不为空就关闭连接}}};}.start();}}
我们首先给sendHttpRequest()方法添加了一个HttpCallbackListener参数,并在方法的内部开启了一个子线程,然后在子线程里去执行具体的网络操作。注意子线程中是无法通过return语句来返回数据的。

这时候又有人会说这是为什么呢?

其实很简单,因为run()方法是没有返回值的。大家可以看看上面线程中的run()方法就知道了。

接下来怎么办?既然无法通过return语句返回数据,那么我们可以将服务器响应的数据传入HttpCallbackListener的onFinish()方法中,如果出现了异常就将异常原因传入到onError()方法中。

现在sendHttpRequest()方法接收两个参数了,因此我们在调用它的时候还需要将HttpCallbackListener的实例传入,如下所示:

HttpUtil.sendHttpRequest(address, new HttpCallbackListener() {@Overridepublic void onFinish(String response) {Log.d("TAG", response.toString());}@Overridepublic void onError(Exception e) {}});
这样的话,当服务器成功响应的时候我们就可以在onFinish()方法里对响应的数据进行处理了,类似地,如果出现了异常,就可以在onError()方法里对异常情况进行处理。如此一来,我们就其巧妙的利用回调机制将响应的数据成功返回给调用方了。

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

每天进步一点点,加油!





0 0
原创粉丝点击