Android HTTP 请求方式 HttpClient

环境准备

  • Java 开发时,后台的 Http 请求操作通常使用的是 org.apache.http.client.HttpClient,Android 开发同样可以使用这些第三方 API。
  • 单纯就使用 Apache 的 HttpCLient 来说,Android 编码 与 Java 编码中 API 使用都是基本一样。

HttpClient 依赖

  • 本人使用的是 Android Studio 3.1.2,第一步就是需要导入 Apache 的 HttpClient 依赖。

  • 上面是在线下载依赖的方式,如果不能翻墙的,也可以直接和 Java 编程一样,将下载好的 Jar 包手动添加进项目的 libs 目录中

被请求的服务器

  • 现在开启一个用于被 Android 请求的服务端地址,本人使用 IDEA 新建一个 Spring Boot 项目来做 web 服务端。

Android Http get 请求

  • 效果图如下所示,点击按钮开始进行 get 请求,请求成功时如下左图所示,之后关闭 web 服务器端,再次请求时如右图所示,显然连接失败。

  • 布局文件 activity_main.xml 文件内容如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/buttonLogin"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="点我" />
</LinearLayout>
  • Http 操作的帮助类/工具类内容如下:
package com.lct.www.yuan.helper;

import android.util.Log;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

/**
 * Http 帮助类
 */
public class HttpHelper {

    /**
     * http get 请求
     */
    public static String httpGetRequest() {
        /**
         * 设置 Http 请求参数
         * 设置请求超时 20 秒
         * 设置等待数据超时10秒
         */
        HttpParams httpParameters = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParameters, 20 * 1000);
        HttpConnectionParams.setSoTimeout(httpParameters, 10 * 1000);
        HttpClient httpclient = new DefaultHttpClient(httpParameters);

        /**
         * 网络访问时 主机地址必须写 域名或者实际 ip 地址
         * 需要注意的是在自己电脑上测试时,服务器也在本机,一不小心就写成了 http://localhost:8080/coco/getTest
         * 或者 127.0.0.1 这种写法会抛异常的
         */
        String uriPath = "http://192.168.1.20:8080/coco/getTest";
        String result;
        HttpGet httpGet = new HttpGet(uriPath);
        int statusCode = -1;
        try {
            HttpResponse httpResponse = httpclient.execute(httpGet);
            statusCode = httpResponse.getStatusLine().getStatusCode();
            Log.i("Wmx logs::", "statusCode=" + statusCode);
            if (statusCode == 200) {//200表示连接成功,403表示拒绝访问
                HttpEntity httpEntity = httpResponse.getEntity();
                /**获取服务返回的数据*/
                result = EntityUtils.toString(httpEntity, "utf-8");
                Log.i("Wmx logs::", "result=" + result);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            return "请求失败,错误代码" + statusCode;
        } catch (IOException e) {
            e.printStackTrace();
            return "请求失败,错误代码" + statusCode;
        } finally {
            /**
             * 操作完成后,关闭连接,释放资源
             */
            if (!httpGet.isAborted()) {
                Log.i("Wmx logs::", "abort Client Connection Request");
                httpGet.abort();
            }
        }
        return "请求成功...";
    }
}
  • 主活动 MainActivity.java 文件内容如下:
package com.lct.www.yuan;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.lct.www.yuan.helper.HttpHelper;

public class MainActivity extends AppCompatActivity {


    private Button buttonLogin;

    /**
     * 自定义 Handler 用于 UI 主线程与 http 操作的子线程之间进行通信
     */
    private Handler myHandler = new Handler() {
        /**
         * 接收 http 操作的子线程传来的数据
         * @param message
         */
        @Override
        public void handleMessage(Message message) {
            /**
             * android.os.Bundle 就是消息 Message 中的数据
             * android.os.BaseBundle#getString(java.lang.String):取值的 key 不存在时,返回 null
             * */
            Bundle bundle = message.getData();
            String messageText = bundle.getString("messageText");
            Toast.makeText(getApplicationContext(), messageText, Toast.LENGTH_SHORT).show();
        }
    };

    /**
     * 活动被创建时触发
     *
     * @param savedInstanceState
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i("Wmx logs::", "活动创建...");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        bindViews();
    }

    /**
     * 视图绑定
     */
    private void bindViews() {
        buttonLogin = findViewById(R.id.buttonLogin);

        buttonLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i("Wmx logs::", "点我.....");
                /**
                 * Android 的网络操作必须新开线程,与 UI 线程分离开来
                 * 新开线程进行 Http 请求
                 */
                new Thread() {
                    @Override
                    public void run() {
                        Log.i("Wmx logs::", "网络访问新线程=" + Thread.currentThread().getName());
                        String feedback = HttpHelper.httpGetRequest();

                        /**将 Http 请求的结果消息传递给 UI 主线程进行显示*/
                        Message message = myHandler.obtainMessage();
                        Bundle bundle = message.getData();
                        bundle.putString("messageText", feedback);
                        myHandler.sendMessage(message);
                    }
                }.start();
            }
        });
    }
}
  • 因为需要做网络访问,所以必须在全局配置文件 AndroidManifest.xml 中添加权限:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.lct.www.yuan"
    android:installLocation="internalOnly">

    <!--添加网络访问权限-->
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

至此编码完成,控制台输出如下:

I/Wmx logs::: 点我.....
I/Wmx logs::: 网络访问新线程=Thread-1349
I/Wmx logs::: statusCode=200
I/Wmx logs::: result={"message":"get Test success"}
              abort Client Connection Request

  • 后台的 Http get 请求与 web 前端请求后台的 get 请求是一样的,同样可以在请求的时候直接在地址 "?" 后面追加请求参数,多个参数时用 & 符合分隔。
  • 直接可以将参数拼接在地址 "?" 后,如果传递的数据量比较大,建议使用 post 请求,而且对于如果需要发送 中文,则建议先对参数进行编码,否则容易乱码。
  • 其它代码仍然和上面一致,现在在 HttpHelper 中新增一个方法,测试 get 请求的同时传递参数:

    /**
     * get 请求的同时传递参数
     *
     * @return
     */
    public static String httpGetRunByParam() {

        /**对于传递的中文数据,建议先进行 url 编码*/
        List<BasicNameValuePair> params = new LinkedList<>();
        params.add(new BasicNameValuePair("userName", "华安"));
        params.add(new BasicNameValuePair("address", "杭州"));
        String param = URLEncodedUtils.format(params, "UTF-8");

        /**
         * 设置 Http 请求参数
         * 设置请求超时 20 秒
         * 设置等待数据超时10秒
         */
        HttpParams httpParameters = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(httpParameters, 20 * 1000);
        HttpConnectionParams.setSoTimeout(httpParameters, 10 * 1000);
        HttpClient httpclient = new DefaultHttpClient(httpParameters);

        /**
         * 网络访问时 主机地址必须写 域名或者实际 ip 地址
         * 需要注意的是在自己电脑上测试时,服务器也在本机,一不小心就写成了 http://localhost:8080/coco/getTest
         * 或者 127.0.0.1 这种写法会抛异常的
         * 1) get 请求的参数直接拼接在地址的 "?" 后面即可
         */
        String uriPath = "http://192.168.1.20:8080/coco/getTest?id=9527&" + param;
        String result;
        HttpGet httpGet = new HttpGet(uriPath);
        int statusCode = -1;
        HttpResponse httpResponse = null;
        try {
            httpResponse = httpclient.execute(httpGet);
            statusCode = httpResponse.getStatusLine().getStatusCode();
            Log.i("Wmx logs::", "statusCode=" + statusCode);
            if (statusCode == 200) {//200表示连接成功,403表示拒绝访问
                HttpEntity httpEntity = httpResponse.getEntity();
                /**获取服务返回的数据*/
                result = EntityUtils.toString(httpEntity, "utf-8");
                Log.i("Wmx logs::", "result=" + result);
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            return "请求失败,错误代码" + statusCode;
        } catch (IOException e) {
            e.printStackTrace();
            return "请求失败,错误代码" + statusCode;
        } finally {
            /**
             * 操作完成后,关闭连接,释放资源
             */
            if (!httpGet.isAborted()) {
                Log.i("Wmx logs::", "abort Client Connection Request");
                httpGet.abort();
            }
        }
        return "请求成功...";
    }
  • 此时 web 服务器端的请求接口修改如下,获取 Android 中 get 请求传递来的参数:
    /**
     * 请求地址:http://localhost:8080/coco/getTest
     */
    @RequestMapping(value = "getTest")
    public void getTest(String id, String userName, String address, HttpServletResponse response) {
        try {
            System.out.println(new Date() + " 被人家访问了...id=" + id + "\tuserName=" + userName + "\taddress=" + address);

            PrintWriter printWriter = response.getWriter();
            printWriter.write("{\"message\":\"get Test success\"}");
            printWriter.flush();
            printWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

输出如下:

Sun Sep 30 16:13:02 CST 2018 被人家访问了...id=9527    userName=华安    address=杭州

Android Http post请求

  • post 请求通常用于传递数据,其它代码不变,仍然在HttpHelper 中新增一个方法,测试 post 请求的同时传递参数:
/***
     * post 请求——————通常用于推送数据
     *
     * @throws IOException
     */
    public static final String httpPostMessage() {
        HttpPost httpPost = null;
        String uriPath = "http://192.168.1.20:8080/coco/postTest";
        int statusCode = -1;
        String result;
        try {
            /**设置请求参数
             * 设置请求超时 20 秒
             * 设置等待数据超时 10 秒
             * */
            HttpParams httpParameters = new BasicHttpParams();
            HttpConnectionParams.setConnectionTimeout(httpParameters, 20 * 1000);
            HttpConnectionParams.setSoTimeout(httpParameters, 10 * 1000);

            /**
             * 设置 post 传递的数据
             * 为 HttpPost 设置推送的内容,使用 utf-8 编码
             */
            List<NameValuePair> params = new ArrayList<>();
            params.add(new BasicNameValuePair("id", "9527"));
            params.add(new BasicNameValuePair("name", "宁王"));
            params.add(new BasicNameValuePair("info", "造反啦"));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");

            httpPost = new HttpPost(uriPath);
            httpPost.setEntity(entity);

            HttpClient httpclient = new DefaultHttpClient(httpParameters);
            HttpResponse httpResponse = httpclient.execute(httpPost);
            statusCode = httpResponse.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                HttpEntity httpEntity = httpResponse.getEntity();
                result = EntityUtils.toString(httpEntity, "utf-8");
                Log.i("Wmx logs::", "服务器返回=" + result);
            } else {
                return "请求失败,错误代码:" + statusCode;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "请求失败,错误代码:" + statusCode;
        } finally {
            /**无论成功与否都要释放连接,并关闭*/
            if (httpPost != null && !httpPost.isAborted()) {
                httpPost.abort();
            }
        }
        return "请求成功:" + result;
    }
  • 此时 web 服务端后台相应的新增一个用于被 post 请求的接口:
    /**
     * post 请求地址:http://localhost:8080/coco/postTest
     */
    @RequestMapping(value = "postTest", method = RequestMethod.POST)
    public void postTest(String id, String name, String info, HttpServletResponse response) {
        try {
            System.out.println(new Date() + " 被人家访问了...id=" + id + "\tname=" + name + "\taddress=" + info);

            PrintWriter printWriter = response.getWriter();
            printWriter.write("{\"message\":\"get Test success\"}");
            printWriter.flush();
            printWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

web 服务器端控制台输出如下:

Sun Sep 30 16:41:11 CST 2018 被人家访问了...id=9527    name=宁王    address=造反啦

Android 控制台输出如下:

I/Wmx logs::: 点我.....
I/Wmx logs::: 网络访问新线程=Thread-1512
I/Wmx logs::: 服务器返回={"message":"get Test success"}

  • 同理还有:org.apache.http.client.methods.HttpDelete、org.apache.http.client.methods.HttpPut 都是同理,不再累述。

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/82910023