在Android开发中我们会接触到数据的交互,比如写入数据、读取数据等,因此我们需要使用通讯间的协议来进行请求,最常见的协议是HTTP协议,而GET和POST则是HTTP协议中最常用的两种请求方式。
GET | POST |
---|---|
一般是从服务器上获取数据 | 一般用来上传表单到服务器1 |
URL 可见,安全性低 | URL 不可见,安全性高 |
提交的数据有长度限制 | 提交的数据无长度限制 |
数据可缓存 | 数据不可缓存 |
通过拼接URL进行参数传递 | 数据放在请求体中发送 |
现在一般使用安全性较高的POST进行请求,在发送密码或其他敏感信息时一定不能使用 GET。POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。GET的数据在 URL 中对所有人都是可见的。
Android进行网络请求有三种方法:HttpURLConnection、 HttpClient以及OkHttp。
HttpClient由于存在API数量过多、扩展困难等缺点,在Android6.0系统中,该功能已经被正式弃用。而原生的HttpURLConnection是JDK里提供的联网API,但是由于网络操作涉及到异步以及多线程,自己使用原生API编写比较麻烦,所以实际开发更偏向于直接使用第三方网络通信库,而我们今天要介绍的OkHttp就属于众多网络通信库中做的最出色的一个。
compile 'com.squareup.okhttp3:okhttp:3.6.0'
<uses-permission android:name="android.permission.INTERNET"/>
如果使用了不安全的http链接,应该在在清单文件中声明:
android:usesCleartextTraffic="true"
<Button
android:id="@+id/btn_request"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求数据"/>
<Button
android:id="@+id/btn_jump"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="跳转解析页"/>
<TextView
android:id="@+id/tv_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://106.53.96.124/wanted/public/index.php/index/article/find")
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
btn_request.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
sendRequestWithOkHttp();//该方法封装了以上1-4步的内容
}
}).start();
}
});
private void sendRequestWithOkHttp(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://106.53.96.124/wanted/public/index.php/index/article/find")
.build();
//try catch进行异常捕捉
try {
//同步写法
Response response = client.newCall(request).execute();
String responseData = response.body().string();
//由于我们进行网络请求是在子线程执行,因此获取到的数据需要从子线程传递到主线程的Ui界面才能显示
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_data.setText(responseData);
}
});
}catch (Exception e){
e.printStackTrace();
}
}
同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。当前主线程会阻塞,直到子线程通知主线程为止。
(提交请求 → 等待服务器处理 → 处理完毕返回)
异步方法调用通常会在另外一个线程中继续执行。整个过程,不会阻碍调用者的工作。主线程可以继续干其它的事情,当子线程完成任务的时候通知一下主线程就可以了,类似于接口回调或消息队列的思想。
(请求通过事件触发>服务器处理(无需等待,主线程可以做别的事)>处理完毕)
两者比较更推荐使用异步方法进行网络请求。
定义一个Call对象,并把把request传给call,通过call调用.enqueue()方法执行。需要给enqueue()方法传一个Callback接口的匿名实现类(包含了onFailure()和onRresponse()方法)。
以下是异步监听方法示例:
private void sendRequestWithOkHttp(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://106.53.96.124/wanted/public/index.php/index/article/find")
.build();
//异步监听写法
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
String jsonData = response.body().string();
// 传递到主线程UI界面
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_data.setText(jsonData);
}
});
}
});
}
一般来说通过网络请求获取到的数据有很多种,xml格式数据、Json格式数据等。我们以上通过网络请求获取到的数据就是Json格式数据。
比如
{
"name":"alex","age":"18","friends":[{
"name":"Amy","age":"19"},{
"name":"Jack","age":"18"}]}
以上{}中相当于是一个类的实例,[{},{}]相当于是一个有两个类组成的数组,包括了两个类的实例。
implementation 'com.google.code.gson:gson:2.7'
private void parseJSONWithGSON(){
Gson gson = new Gson();
//由于我们这里需要解析的Json数据中包含了数组,所以需要使用TypeToken将期望解析成数据类型传入到fromJson()方法中
BaseResponse<List<BaseResponse.Article>> baseResponse = gson.fromJson(jsonData,new TypeToken<BaseResponse<List<BaseResponse.Article>>>(){
}.getType());
List<BaseResponse.Article> articleList = baseResponse.getData();
Log.d("code", "code is " + baseResponse.getCode());
Log.d("msg", "msg is " + baseResponse.getMsg());
for (BaseResponse.Article article:articleList){
Log.d("Data", "id is "+article.getId());
Log.d("Data", "title is "+article.getTitle());
Log.d("Data", "content is "+article.getContent());
Log.d("Data", "tags is "+article.getTags());
Log.d("Data", "create_time is "+article.getCreate_time());
Log.d("Data", "writer is "+article.getWriter());
Log.d("Data", "images is "+article.getImages());
Log.d("Data", "photo is "+article.getPhoto());
Log.d("Data", "like_number is "+article.getLike_number());
Log.d("Data", "comment_number is "+article.getComment_number());
}
}
btn_show.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (jsonData==null){
Toast.makeText(MainActivity.this,"数据为空",Toast.LENGTH_SHORT).show();
}
else parseJSONWithGSON();
}
});
File→setting→plugin→Marketplace,搜索gsonformat/Sgsonformat/gsonfromatplus,通过alt+insert唤出gsonformat插件,复制json格式数据点击ok。
接口测试:https://getman.cn/
接口文档:http://www.docway.net/
参考资料:
Android入门之Http请求方式Get与Post
同步和异步的区别
同步(Synchronous)和异步(Asynchronous)
一般用来上传表单(数据集合)到服务器,服务器处理后再返回数据给客户端。 ↩︎