环境准备
- 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 都是同理,不再累述。