前言:

本文总结了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与服务器的交互方式和数据类型,并总结了在实际项目的简单运用,数据格式的运用场景远不止上面提到的几种场景,后期会持续完善,如有不足之处,欢迎指出。

参考资料:

1.Android手机访问服务器的一种数据交互方法

2.App架构设计经验谈:接口的设计 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

浅谈Android客户端与服务器的数据交互总结的更多相关文章

  1. html5 canvas合成海报所遇问题及解决方案总结

    这篇文章主要介绍了html5 canvas合成海报所遇问题及解决方案总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  4. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  5. Ionic – Splash Screen适用于iOS,但不适用于Android

    我有一个离子应用程序,其中使用CLI命令离子资源生成的启动画面和图标iOS版本与正在渲染的启动画面完美配合,但在Android版本中,只有在加载应用程序时才会显示白屏.我检查了config.xml文件,所有路径看起来都是正确的,生成的图像出现在相应的文件夹中.(我使用了splash.psd模板来生成它们.我错过了什么?这是config.xml文件供参考,我觉得我在这里做错了–解决方法在config.xml中添加以下键:它对我有用!

  6. ios – 无法启动iPhone模拟器

    /Library/Developer/CoreSimulator/Devices/530A44CB-5978-4926-9E91-E9DBD5BFB105/data/Containers/Bundle/Application/07612A5C-659D-4C04-ACD3-D211D2830E17/ProductName.app/ProductName然后,如果您在Xcode构建设置中选择标准体系结构并再次构建和运行,则会产生以下结果:dyld:lazysymbolbindingFailed:Symbol

  7. Xamarin iOS图像在Grid内部重叠

    heyo,所以在Xamarin我有一个使用并在其中包含一对,所有这些都包含在内.这在Xamarin.Android中看起来完全没问题,但是在Xamarin.iOS中,图像与标签重叠.我不确定它的区别是什么–为什么它在Xamarin.Android中看起来不错但在iOS中它的全部都不稳定?

  8. 在iOS上向后播放HTML5视频

    我试图在iPad上反向播放HTML5视频.HTML5元素包括一个名为playbackRate的属性,它允许以更快或更慢的速率或相反的方式播放视频.根据Apple’sdocumentation,iOS不支持此属性.通过每秒多次设置currentTime属性,可以反复播放,而无需使用playbackRate.这种方法适用于桌面Safari,但似乎在iOS设备上的搜索限制为每秒1次更新–在我的情况下太慢了.有没有办法在iOS设备上向后播放HTML5视频?解决方法iOS6Safari现在支持playbackRat

  9. 使用 Swift 语言编写 Android 应用入门

    Swift标准库可以编译安卓armv7的内核,这使得可以在安卓移动设备上执行Swift语句代码。做梦,虽然Swift编译器可以胜任在安卓设备上编译Swift代码并运行。这需要的不仅仅是用Swift标准库编写一个APP,更多的是你需要一些框架来搭建你的应用用户界面,以上这些Swift标准库不能提供。简单来说,构建在安卓设备上使用的Swiftstdlib需要libiconv和libicu。通过命令行执行以下命令:gitclonegit@github.com:SwiftAndroid/libiconv-libi

  10. Android – 调用GONE然后VISIBLE使视图显示在错误的位置

    我有两个视图,A和B,视图A在视图B上方.当我以编程方式将视图A设置为GONE时,它将消失,并且它正下方的视图将转到视图A的位置.但是,当我再次将相同的视图设置为VISIBLE时,它会在视图B上显示.我不希望这样.我希望视图B回到原来的位置,这是我认为会发生的事情.我怎样才能做到这一点?编辑–代码}这里是XML:解决方法您可以尝试将两个视图放在RelativeLayout中并相对于彼此设置它们的位置.

随机推荐

  1. Flutter 网络请求框架封装详解

    这篇文章主要介绍了Flutter 网络请求框架封装详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. Android单选按钮RadioButton的使用详解

    今天小编就为大家分享一篇关于Android单选按钮RadioButton的使用详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. 解决android studio 打包发现generate signed apk 消失不见问题

    这篇文章主要介绍了解决android studio 打包发现generate signed apk 消失不见问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  4. Android 实现自定义圆形listview功能的实例代码

    这篇文章主要介绍了Android 实现自定义圆形listview功能的实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. 详解Android studio 动态fragment的用法

    这篇文章主要介绍了Android studio 动态fragment的用法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. Android用RecyclerView实现图标拖拽排序以及增删管理

    这篇文章主要介绍了Android用RecyclerView实现图标拖拽排序以及增删管理的方法,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下

  7. Android notifyDataSetChanged() 动态更新ListView案例详解

    这篇文章主要介绍了Android notifyDataSetChanged() 动态更新ListView案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下

  8. Android自定义View实现弹幕效果

    这篇文章主要为大家详细介绍了Android自定义View实现弹幕效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Android自定义View实现跟随手指移动

    这篇文章主要为大家详细介绍了Android自定义View实现跟随手指移动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Android实现多点触摸操作

    这篇文章主要介绍了Android实现多点触摸操作,实现图片的放大、缩小和旋转等处理,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部