Android 中发起 HTTP 网络请求的方法有很多种,在刚开始学 Android 的时候,我总是比较倾向于使用原生提供的 API,其一是因为不需要导入第三方的依赖,其二是因为代码量也不多,而在实习后才发现,框架原来如此方便。

比如我需要写一个登录功能,希望使用 POST 方式提交,先来看看原生中的 HttpURLConnection

private void sendRequestWithHttpURLConnection(final String tel, final String password) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            HttpURLConnection httpURLConnection = null;
            try {
                URL url = new URL("http://url");        // 接口
                String data = "tel=" + tel + "&password=" + password;
                httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setConnectTimeout(8000);      // 设置连接超时时间
                httpURLConnection.setReadTimeout(8000);         // 设置读取超时时间
                httpURLConnection.setRequestMethod("POST");     // 设置以 Post 方式提交数据
                DataOutputStream out = new DataOutputStream(httpURLConnection.getOutputStream());
                out.writeBytes(data);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (httpURLConnection != null) {
                    httpURLConnection.disconnect();
                }
            }
        }
    }).start();
}

这里省略了部分代码,包括得到数据后的解析以及校验等等,代码并不多嘛,但是实际上跑起来就是,服务器上没有接收到我提交的数据。

几经周折,终于把残缺的代码补全了:

private void sendRequestWithHttpURLConnection(final String tel, final String password) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            HttpURLConnection httpURLConnection = null;
            try {
                URL url = new URL("http://url");        // 接口
                String data = "tel=" + tel + "&password=" + password;
                httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setConnectTimeout(8000);      // 设置连接超时时间
                httpURLConnection.setReadTimeout(8000);         // 设置读取超时时间
                httpURLConnection.setDoOutput(true);            // 打开输出流,以便向服务器提交数据
                httpURLConnection.setRequestMethod("POST");     // 设置以 Post 方式提交数据
                httpURLConnection.setUseCaches(false);          // 使用 Post 方式不能使用缓存
                httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");      //设置请求体的类型是文本类型
                httpURLConnection.setRequestProperty("Content-Length", data.length() + "");     // 设置请求体的长度

                httpURLConnection.connect();        // 建立连接

                httpURLConnection.getOutputStream().write(data.getBytes());

                int code = httpURLConnection.getResponseCode(); // 服务器的响应码 200 OK //404 页面找不到
                // // 503服务器内部错误
                if (code == 200) {
                    InputStream is = httpURLConnection.getInputStream();
                    // 把is的内容转换为字符串
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int len = -1;
                    while ((len = is.read(buffer)) != -1) {
                        bos.write(buffer, 0, len);
                    }
                    String result = new String(bos.toByteArray());
                    is.close();
                    Toast.makeText(LoginActivity.this, result, Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(LoginActivity.this, "请求失败,失败原因: " + code, Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (httpURLConnection != null) {
                    httpURLConnection.disconnect();
                }
            }
        }
    }).start();
}

我认为最重要的可能是这句:

httpURLConnection.connect();        // 建立连接

网上大多数的资料都没有提到,我就不知道他们是怎么连接的了,当我把这句代码补上后,App 才成功和服务器建立起连接。

另外下方关于服务器响应码的那段代码也是必须的,得到响应码,判断与服务器连接是否正常,没了这个判断就不能和服务器进行数据的交互。

这样看下来,跟一开始的“代码并不多”差距就太大了,代码冗余晦涩,阅读起来十分痛苦,于是便打算对这段代码进行重构。

之前阅读『第一行代码——Android』时有学习过 OkHttp,所以我就打算使用它来代替 HttpURLConnection

为什么我虽然从一开始就知道这个网络通信库却不使用呢?因为前文也提到,我以为 HttpURLConnection 的代码量相比 OkHttp 并没有多出多少,但是出现了如此巨大的 Bug,修复完成后代码量居然增加了一倍,所以必须转投 OkHttp 的怀抱。

首先在项目中添加 OkHttp 库的依赖:

dependencies {
    implementation 'com.squareup.okhttp3:okhttp:(insert latest version)'
}

为了使其保持最新版本,最好登录其官网或者其 Github 项目主页进行查询,当然,添加依赖时『Android Studio』内也会有提示。

然后就可以在项目中使用了,将上方的代码进行改造,就可以得出一段简洁的代码:

private void sendRequestWithOkHttp(final String tel, final String password) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                OkHttpClient client = new OkHttpClient();
                RequestBody requestBody = new FormBody.Builder()
                        .add("tel", tel)
                        .add("password", password)
                        .build();
                Request request = new Request.Builder()
                        .url("http://url")      // 接口
                        .post(requestBody)
                        .build();
                Response response = client.newCall(request).execute();
                String responseCode = response.body().string();
                Log.e("GETCODE", responseCode);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

真的太好用了有木有!如此清晰简单的代码就完成了上面的内容,并且还十分容易获取从服务器返回的数据,方便我后面对其进行解析,简直要爱上它了!