這篇文章主要介紹了淺談Android客戶端與服務器的數據交互總結,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨着小編來一起學習學習吧
前言:
本文總結了Android客戶端與服務器進行交互時,採用RESTful API +Json的交互方式,針對不同的數據形式以及不同的解析方法,如有不足之處,歡迎指正。
溫馨提示:本文適合有一定Android開發經驗的人閱讀,如有疑問,歡迎留言討論。
先了解一下相關的基本概念。
1. Android客戶端與服務器端通信方式
通信方式主要有HTTP和Socket。
- HTTP通信:即使用HTTP協議進行通信,工作原理是客戶端向服務器端發送一條HTTP請求,服務器收到之後先解析客戶端的請求,之後會返回數據給客戶端,然後客戶端再對這些數據進行解析和處理。HTTP連接採取的是“請求—響應”方式,即在請求時建立連接通道,當客戶端像服務器端發送請求時,服務器端才能向客戶端發送數據。
- Socket通信:Socket又稱套接字,在程序內部提供了與外界通信的端口,即端口通信。通過建立socket連接,可爲通信雙方的數據傳輸傳提供通道。Socket的主要特點有數據丟失率低,使用簡單且易於移植。Socket類似於peer to peer的連接,一方可隨時向另一方喊話。
小結:HTTP和Socket都是基於TCP協議的。使用兩種通信方式的情況是:
1.使用HTTP的情況:雙方不需要時刻保持連接在線,比如客戶端資源的獲取、文件上傳等。
2.使用UDP的情況:大部分即時通訊應用(QQ、微信)、聊天室、蘋果APNs等。
2. Android客戶端與服務器的數據交互方式
主要有三種:
- 數據流
從web服務器響應到手機終端的數據 一般打包在一個字節數組中,這個字節數據中包含了不同的數據類型,客端端採取Java數據流和過慮流的方式從字節數組中取出各種類型的數據。
這種交互方式我在學習Android之初用過,實際項目中並沒有發現哪家公司在用。這種方式了擴展了Android平臺在訪問Web服務器進行交互時的解析數據能力,僅供研究學習。
- XML
Webservice的標準數據格式。
- Protocol Buffers
Protocol Buffers 是一種輕便高效的結構化數據存儲格式,支持跨平臺。它很適合做數據存儲或 RPC 數據交換格式。比 JSON 最大的優點就是傳輸的時候數據體積可以壓縮很小,傳輸效率比較高。本人在這個在項目中沒有用到過。
- JSON
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。 易於人閱讀和編寫。同時也易於機器解析和生成。毫無疑問,大家最常用。
本文重點會介紹關於json數據格式 的常用格式。
json數據格式 的採用,根據業務情況,一般是團隊中的共識。技術的迭代更新,到後期基本都會考慮多個平臺的通用性、可移植性和可讀性。比如 我們開發團隊,有移動端開發(Android、iOS)、前端開發(H5開發)和後臺開發(golang開發)。
關於服務器的開發規範,我們先來了解一下。
服務器開發規範 我們採用的是 RESTful,RESTful是目前最流流行的 API設計規範,用於web數據接口的設計。
3. 爲什麼要使⽤RESTful API
- ⾯面向資源(URI),具有解釋性;
- 行爲(GET / POST / PUT / PATCH / DELETE)與資源(URI)分離,更更加輕量量;
- 數據描述簡單,使⽤用JSON、XML、Protocol Buffers即可全覆蓋,主要使用JSON;
它的核心原則是定義用少量方法就能操作的命名資源。資源和方法可視爲API的名詞和動詞。
4. http請求方式
- GET :讀取(Read)
- POST :新建(Create)
- PUT :更新(Update),通常是全部更更新
- PATCH :更新(Update),通常是部分更更新
- DELETE :刪除(Delete)
項目搭建之始,客戶端和服務器一般用 Get 和Post的方式來交互,隨着業務的演進和技術的規範迭代,到後期我們都得按規範來。於是 我們採用了上述幾種方式來設計服務器接口,相應地,移動端的請求方式也得與之對應。
至此,不在贅述RESTful API的設計規範,可自行百度瞭解更多。
5. Json交互數據類型實際中的運用
接口的數據一般都採用JSON格式進行傳輸,不過,需要注意的是,JSON的值只有六種數據類型:
- Number:整數或浮點數
- String:字符串
- Boolean:true 或 false
- Array:數組包含在方括號[]中
- Object:對象包含在大括號{}中
- Null:空類型
傳輸的數據類型不能超過這六種數據類型,不能用Date數據類型,不同的解析庫解析方式不同,可能會導致異常,如果遇到日期的數據,最好的方式就是使用毫秒數表示日期。
5.1 String的數據類型
使用場景:如用戶退出登錄時,只需要得到返回狀態和提示信息即可,不需要返回任何數據。
{ "code": 1000, "message": "成功" }
數據解析工具類:
abstract class BaseStringCallback: BaseCallback() { override fun onSuccess(data: String) { val responseData = JSONObject(data) val code = responseData.getInt("code") val message = responseData.getString("message") if (code == 1000) { success(message) } else { //其他狀態 } } abstract fun success(msg: String) }
調用時(僞代碼):
LogoutApi.execute(object : BaseStringCallback() { override fun success(msg: String) { //處理數據 })
5.2 Object數據類型
識別標示爲:{}
使用場景:如獲取當前用戶信息,返回owner實體類,這個類我們可以直接用Gson的工具類轉換爲owner實體類。
{ "code": 1000, "message": "成功", "resp": { "owner": { "id": 58180, "name": "張三", "idCert": "", "certType": 1, "modifier": "jun5753", "updateTime": 1567127656436 }, } }
Json數據轉換爲實體類工具類:
abstract class BaseObjectCallback<T>(private val clazz: Class<T>) : BaseCallback() { override fun onSuccess(data: String) { val responseData = JSONObject(data) val code = responseData.getInt("code") val message = responseData.getString("message") if (code == 1000) { val disposable = Observable.just(responseData) .map { it.getJSONObject("resp").toString() } .map { JsonUtil.parseObject(it, clazz)!! } .applyScheduler() .subscribe( { success(it) }, { //異常時處理 }) } else { //其他狀態時處理 } } abstract fun success(data: T) }
調用時(僞代碼):
LaunchApi.getOwerInfo.execute(object : BaseObjectCallback<OwnerEntity>(OwnerEntity::class.java) { override fun success(data: OwnerEntity) { //處理數據 })
5.3. Array數據類型
識別標示爲:[]
使用場景:如獲取聯繫人列表,返回的數據是contact列表,如 ArrayList<contact >。
{ "code": 1000, "message": "成功", "resp": { "contact": [ { "id": 5819, "name": "來啦", "phone": "", "address": "哈哈哈", "province": "湖南省", "city": "長沙市", "area": "芙蓉區", "modifier": "jun5753", "isOwner": 0, "updateTime": 1566461377761 }, { "id": 5835, "name": "小六", "phone": "13908258239", "address": "天安門", "province": "北京市", "city": "北京市", "area": "東城區", "modifier": "jun5753", "isOwner": 0, "updateTime": 1567150580553 } ] } }
Json數據轉換爲實體類列表工具類:
abstract class BaseArrayCallback<T>(private val clazz: Class<T>) :BaseCallback() { override fun onSuccess(data: String) { val responseData = JSONObject(data) val code = responseData.getInt("code") val message = responseData.getString("message") if (code == 1000) { val disposable = Observable.just(responseData) .map { it.getJSONArray("resp").toString() } .map { JsonUtil.parseArray(it, clazz)!! } .applyScheduler() .subscribe( { success(it) }, { //異常時處理 }) } else { //其他狀態時處理 } } abstract fun success(data: ArrayList<T>) }
調用時(僞代碼):
LaunchApi.getContactList.execute(object : BaseArrayCallback<ContactEntity>(ContactEntity::class.java) { override fun success(data: ArrayList<ContactEntity>) { //處理數據 })
5.4 複雜數據格式
使用場景:如用戶的篩選數據需要上傳到服務器,每次進入篩選界面時先從服務器獲取最新數據信息。
返回的篩選json數據如下所示:
{ "code": 1000, "message": "成功", "resp": { "filterdata": [ 321, 671 ], }
此時的數據 不同於上面提到的幾種Json數據類型,返回的列表中 數據沒有key,只有value值 。並不是以鍵值對(key-value)返回的。
解析方法:
聲明實體類
class FilterEntity { /** 篩選的數據:解析數組對象 爲Int 型數據 ArrayList<Int> */ var filterdata = ArrayList<Int>() }
調用方法(僞代碼):
HomeApi.getFilterData() .execute(object : CJJObjectCallback<FilterEntity>(FilterEntity::class.java) { override fun success(data: FilterEntity) { //處理數據 } })
當用戶選擇篩選數據後,需要上傳到服務器,僞代碼如下:
//上傳json示例爲:[0,1,2,3,4] val filterList = ArrayList<Int>() //添加int數據 filterList.add(321) filterList.add(671) val jsonData = JsonUtil.toJson(filterList) //上傳服務器 HttpTool.put(FILTER_DATA).param("data", jsonData) //Gson轉換方法 fun toJson(object: Any): String { var str = "" try { str = gson.toJson(object) } catch (e: Exception) { } return str }
更多地,如果想要 上傳多種數據類型,如key-value形式的數據到服務器,僞代碼如下:
//json數據示例:{"group":[22,23,24],"brand":[1,2,3,4]} // 客戶分組篩選 val customerGroupJsonArray = ArrayList<Int>() val map = ArrayMap<String, ArrayList<Int>>() customerGroupList.forEach { customerGroupJsonArray.add(it.id) } map["group"] = customerGroupJsonArray // 品牌篩選 val vehicleBrandJsonArray = ArrayList<Int>() vehicleBrandList.forEach { vehicleBrandJsonArray.add(it.brandId) } map["brand"] = vehicleBrandJsonArray //將map類型的數據轉換爲json數據 val jsonData = JsonUtil.toJson(map) //上傳服務器 HttpTool.put(FILTER_DATA).param("data", jsonData)
6.總結
本文總結了Android與服務器的交互方式和數據類型,並總結了在實際項目的簡單運用,數據格式的運用場景遠不止上面提到的幾種場景,後期會持續完善,如有不足之處,歡迎指出。
參考資料:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持神馬文庫。