文章列表
- 從零開始搭建一個聯網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);
}