從零開始搭建一個聯網小程序(三)—— Android端程序

文章列表

  1. 從零開始搭建一個聯網Android APP(一)—— 工具和基本概念介紹
  2. 從零開始搭建一個聯網Android APP(二)—— 服務器端程序
  3. 從零開始搭建一個聯網Android APP(三)—— Android端程序

本文源碼

注:該工程有兩個branch,master爲離線版本,所有功能集成到Android端,便於使用;online爲在線版本,適合喜歡折騰的人

注:本系列博客主要重點在於服務器端的程序開發、部署和Android端如何與服務器端通信,不涉及具體的Android開發內容。


程序編寫

  這裏主要描述Android端如何與server進行通信並解析返回的Json格式數據。主要涉及兩個主要的庫文件:

  1. okhttp3 —— 用於與server通信
  2. 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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章