网络编程代码重用的一点问题与技巧

来源:互联网 发布:淘宝运费险如何设置 编辑:程序博客网 时间:2024/06/06 02:00

网络编程代码重用的一点问题与技巧

基本的重用代码事例

学习android开发时大家都会接触到发起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);            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();        } finally {            if (reader != null){                try {                    reader.close();                } catch (IOException e){                    e.printStackTrace();                }            }            if (connection != null){                connection.disconnect();            }        }    }}

这样我们只需要传入网址,获取服务器相应的数据后,就可以进行后续的解析和处理了。

String address = "http://blog.dota2.com/"String response = HttpUtil.sendHttpRequest(address);

线程是个问题

网络请求通常都是耗时的操作,而我们的sendHtttpRequest()方法内部并没有开启线程,这样可能会使主线程被阻塞住,这对用户的体验有不好的影响。
但我们恐怕也不能简单地在sendHtttpRequest()方法开启一个线程来解决问题。因为所有的耗时逻辑都在子线程进行的,sendHtttpRequest()方法会在服务器还没来得及响应的时候就执行结束了,导致该方法无法返回相应的数据。
所以我们需要另寻他路。

java的回调机制

我们先来看下面的代码:

public interface HttpCallBackListener {    void onFinish(String response);    void onError(Exception e);}

我们定义了一个接口并在其中定义了两个方法,onFinish()在服务器相应请求时调用,参数是服务器返回的数据,onError()在进行网络操作出现错误时调用,参数是错误的详细信息。
然后修改HttpUtil的代码:

public class HttpUtil{    public static String 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);                    }                    if (listener != null) {                        listener.onFinish(response.toString());                    }                } catch (Exception e){                    if (listener != null) {                        listener.onError(e);                    }                } finally {                    if (reader != null){                        try {                            reader.close();                        } catch (IOException e){                            e.printStackTrace();                        }                    }                    if (connection != null){                        connection.disconnect();                    }                }            }        }).start;    }}

我们给sendHttpRequest()方法添加了一个HttpCallbackListener参数,并在方法的内部开启了一个子线程,由子线程去执行网络操作。由于子线程无法通过return语句返回数据,因此我们将数据传入了HttpCallbackListener的onFinish()方法中,而异常传入了onError()方法中。
现在,调用sendHttpRequest()方法的代码是这样的:

HttpUtil.sendHttpRequest("http://blog.dota2.com/", new HttpCallbackListener() {    @Override    public void onFinish(String response) {        // 根据返回的数据执行具体逻辑    }    public void onError(Exception e) {        // 在此处理异常    }});

如此一来,通过利用回调机制我们就解决了网络编程的线程问题。

使用OKHttp实现回调机制

有句话说得好,不要重复发明伦子,其实OKHttp已经提供了实现相同功能的接口,如下:

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库中自带的一个回调接口,类似于刚才的HttpCallbackListener。在client.newCall()之后调用enqueue()方法,并把okhttp3.Callback参数传入,没错,OkHttp会在enqueue()方法内部自己开好子线程并执行http请求,最终将请求结果回调到okhttp3.Callback当中。
所以,现在我们调用sendOkHttpRequest()方法是这样写:

HttpUtil.sendOkHttpRequest("http://blog.dota2.com/", new okhttp3.Callback() {    @Override    public void onResponse(Call call, Response response) throws IOException {        // 根据返回的数据执行具体逻辑        String responseData = response.body().string();    }    public void onFailure(Call call, IOException e) {        // 在此处理异常    }});

这样,我们只需编写少量的代码就能完成较为复杂的网络操作了。

原创粉丝点击