美文网首页AndroidAndroid开发Android知识
09网络技术-网络编程的最佳实践

09网络技术-网络编程的最佳实践

作者: 何惧l | 来源:发表于2018-03-30 22:12 被阅读166次

    现在已经会使用Http请求了,但是请求的代码都是基本相同的,若每次都重写一遍就太差劲了,通常应该把这些通用的网络操作提取到一个公共类中,并提供一个静态的方法,当想要发起网络请求的时候,就简单的调用这个方法就可以了

    1. 自定义一个类,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();
                }
            }
    
        }
    }
    
    1. 以后每当需要发起一条HTTP请求的时候就可以这样写了
    String address = "http://www.baidu.com"
    String response = HttpUtil.sendHttpRequest(address)
    
    • 在获取服务器响应的数据后,就可以对它进行解析和处理了,但是,要注意的是,网络请求通常是属于耗时的操作,而sendHttpRequest()方法的内部没有开启线程,这样就有可能在调用sendHttpRequest()方法的时候使得主线程被阻塞
    • 这个时候如果在这个sendHttpRequest()方法中开一个线程的话,那么服务器响应的数据是无法进行返回的,所有的耗时逻辑都是在子线程中进行的,这个方法sendHttpRequest()会在服务器还没来的及响应的时候就执行结束了,就没有办法返回数据了
    1. 这个时候就需要使用java的回调机制,先定义一个接口,HttpCallbackListener
    public interface HttpCallbackListener {
        
        void onFinish(String response);
        
        void onError(Exception e);
        
    }
    
    • onFinish()方法表示当服务器成功响应我们请求的时候调用,参数是服务器返回的数据
    • onError()方法表示当进行网络操作出现错误的时候调用,参数是记录错误的详细信息
    1. 修改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()方法中
    1. 现在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()方法中进行处理了
    1. 当然了,使用上面的还有点稍微复杂,那么就是用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当中
    1. 在调用这个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()方法来进行线程的转换,至于为什么这样,以后会学到的

    相关文章

      网友评论

      • IT人故事会:做开发很累,还的学习,之前你这个我也碰到过,但是没记录谢谢了
        何惧l:没事,我是初学者,现在把遇到的问题记录下来,这样方便之后查看

      本文标题:09网络技术-网络编程的最佳实践

      本文链接:https://www.haomeiwen.com/subject/dudwcftx.html