文章列表
- 从零开始搭建一个联网Android APP(一)—— 工具和基本概念介绍
- 从零开始搭建一个联网Android APP(二)—— 服务器端程序
- 从零开始搭建一个联网Android APP(三)—— Android端程序
本文源码
注:该工程有两个branch,master为离线版本,所有功能集成到Android端,便于使用;online为在线版本,适合喜欢折腾的人
注:本系列博客主要重点在于服务器端的程序开发、部署和Android端如何与服务器端通信,不涉及具体的Android开发内容。
程序编写
这里主要描述Android端如何与server进行通信并解析返回的Json格式数据。主要涉及两个主要的库文件:
- okhttp3 —— 用于与server通信
- GSON —— 用于解析Json格式数据
与Server通信
网络请求代码如下:
// GET
public static void sendRequestGetAsy(String address, okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(BASE_URL + address)
.build();
client.newCall(request).enqueue(callback);
}
// POST
public static void addNewAccount(Account account, okhttp3.Callback callback){
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("content", account.getContent())
.add("number", String.format(Locale.CHINA, "%.2f", account.getNumber()))
.add("person", account.getPerson())
.add("createTime", account.getCreateTime())
.build();
Request request = new Request.Builder()
.url(BASE_URL + ADD_ACCOUNT)
.post(requestBody)
.build();
client.newCall(request).enqueue(callback);
}
与server对应,这里也有GET和POST两种方式,GET方式就将参数全部写到address里面传进来就好,POST方式采用键值对的形式将参数添加到body里面。同时为了不阻塞现成,这里都采用异步的方式调用网络请求。
调用方式如下:
GET
private void getAccountInfo(){
String str = HttpUtils.QUERY_ALL_ACCOUNT + OFFSET + "/" + LIMIT;
HttpUtils.sendRequestGetAsy(str, new okhttp3.Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
Log.e(TAG, e.toString());
runOnUiThread(() -> {
swipeRefreshLayout.setRefreshing(false);
showToast("获取账单信息失败,请检查网络连接...");
});
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
try{
assert response.body() != null;
String str = response.body().string();
JSONObject jsonObject = new JSONObject(str);
//子线程不能更新UI相关内容
updateAccountUI((ArrayList<Account>)
HttpUtils.parseAllAccount(jsonObject.getString(ACCOUNTS_INFO)));
if (isRefresh){
runOnUiThread(() -> {
swipeRefreshLayout.setRefreshing(false);
isRefresh = false;
new Handler().postDelayed(() -> showToast("数据更新完毕"), 300);
});
}
}catch (JSONException e){
Log.e(TAG, e.toString());
}
}
});
}
POST
这里直接传入一个自定义类的实例。
解析Json数据
在回调函数内,通过这句话String str = response.body().string();
就可以取出服务器返回的数据内容。具体解析过程如下:
定义一个订单类,然后利用GSON提供的注解函数,标明每个字段对应的json函数键值是什么,然后就可以用GSON自动解析了。
package com.example.account_book;
import com.example.account_book.util.TimeUtils;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
public class Account implements Serializable, Comparable<Account>{
@SerializedName("_account_id")
private int id;
@SerializedName("_content")
private String content;
@SerializedName("_number")
private double number;
@SerializedName("_person")
private String person;
@SerializedName("_create_time")
private String createTime;
public Account(){
this.content = "";
this.number = 0.0;
this.person = "xkw";
this.createTime = TimeUtils.now();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public double getNumber() {
return number;
}
public void setNumber(double number) {
this.number = number;
}
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person = person;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "Time: " + this.createTime + "\n" +
"Content: " + this.content + "\n" +
"Number: " + this.number + "\n" +
"Person: " + this.person;
}
public String getSimpleString() {
return this.createTime + this.content + this.number + this.person;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Account){
Account account = (Account)obj;
return this.createTime.equals(account.getCreateTime());
}
return false;
}
@Override
public int compareTo(Account account) {
return this.createTime.compareTo(account.createTime);
}
}
GSON自动解析
public static List<Account> parseAllAccount(String jsonData){
//使得可以解析Date型变量
Gson gson = new GsonBuilder().setDateFormat(DATE_FORMAT).create();
return gson.fromJson(jsonData, new TypeToken<List<Account>>(){}.getType());
}
public static Account parseAccountDetail(String jsonData){
//使得可以解析Date型变量
Gson gson = new GsonBuilder().setDateFormat(DATE_FORMAT).create();
return gson.fromJson(jsonData, Account.class);
}