手机上的资源毕竟有限,为了获取更丰富的信息,就得到辽阔的互联网大海上冲浪。对于App自身,也要经常与服务器交互,以便获取最新的数据显示到界面上。这个客户端与服务端之间的信息交互,基本使用HTTP协议进行通信,即App访问服务器的HTTP接口来传输数据。HTTP接口调用在Java代码中可不是一个轻松的活,开发者若用最基础的HttpURLConnection来编码的话,至少要考虑以下场景的处理:
1、HTTP的请求方式是什么,是GET还是POST还是PUT还是DELETE?
2、HTTP的连接超时时间是多少,请求应答的超时时间又是多少?
3、HTTP头部的语言和浏览器信息该设置为什么?
4、HTTP传输的数据内容采取的是哪种编码方式?
5、HTTP的应答数据如果是压缩过的,又要如何解压?
6、HTTP的输入输出流需要注意哪些方面?
7、HTTP如何分块传输较大的数据信息?
瞧瞧上面层出不穷的功能要求,如果开发者事必躬亲逐个编码,那可真是要累得够呛。因此,各种意图取代HttpURLConnection的网络交互框架如雨后春笋般涌现出来,既有老资格的如HttpClient,又有后起之秀如Android-Async-Http、Volley、OkHttp、Retrofit等等,可谓是百花齐放、百家争鸣。当然,这些网络框架是需要学习成本的,使用起来也不如想象中的那么容易;它们只是在技术上各有千秋,并非终极的解决方案,往往是你方唱罢我登台,各领风骚几年然后歇菜。
其实HTTP交互原本无需这样大动干戈,常见的接口调用仅仅是App往服务器发送一串请求信息,然后服务器返回给App一串处理结果,这种简单的业务场景已经足够应付大多数App的网络通信需求。所以大道至简,Kotlin把网络交互看作是跟文件读写一样的I/O操作,后端地址就像是个文件路径,那么请求服务器的数据犹如读取文件内容。文本分为文本文件和二进制文件两种,则HTTP接口对应获取文本数据和获取二进制数据两种,于是整个网络请求便简化为数据的存跟取了。
具体到详细的Kotlin编码,文件对象由“File(文件路径)”构建,而HTTP对象由“URL(网络地址)”构建,获取接口数据则有readText和readBytes两个方法,前者用于获取文本形式的应答数据,后者用于二进制形式的应答数据如图片文件、音频文件等等。仅仅一个readText方法真的能完成繁杂的HTTP接口调用操作吗?下面我们通过一个具体的接口访问案例,探讨一下如何使用Kotlin代码实现HTTP接口调用。
智能手机普遍提供了定位功能,可是系统自带的定位服务只能获得用户所在的经纬度信息,而这枯燥的经纬度数字令人不知所云,肯定要把经纬度转换为详细的地址信息才方便用户理解。将经纬度转换为详细地址,就要访问谷歌地图提供的地址查询接口了,该接口的地址形如“http://maps.google.cn/maps/api/geocode/json?请求参数信息”,App把经纬度数据作文请求参数传入,对方会返回一个包含地址信息的json串,通过解析json串即可获得当前的详细地址。由于访问网络需要在分线程进行,因此接口访问代码必须放在doAsync代码块中,下面给出根据经纬度获取详细地址的Kotlin代码片段:

    private val mapsUrl = "http://maps.google.cn/maps/api/geocode/json?latlng={0},{1}&sensor=true&language=zh-CN"

    //位置监听器侦听到定位变化事件,就调用该函数请求详细地址
private fun setLocationText(location: Location?) {
if (location != null) {
doAsync {
//根据经纬度数据从谷歌地图获取详细地址信息
val url = MessageFormat.format(mapsUrl, location.latitude, location.longitude)
val text = URL(url).readText()
val obj = JSONObject(text)
val resultArray = obj.getJSONArray("results")
var address = ""
//解析json字符串,其中formatted_address字段为具体地址名称
if (resultArray.length() > 0) {
val resultObj = resultArray.getJSONObject(0)
address = resultObj.getString("formatted_address")
}
//获得该地点的详细地址之后,回到主线程把地址显示在界面上
uiThread { findAddress(location, address) }
}
} else {
tv_location.text = "$mLocation\n暂未获取到定位对象"
}
} //在主线程中把定位信息连同地址信息都打印到界面上
private fun findAddress(location: Location, address: String) {
tv_location.text = "$mLocation\n定位对象信息如下: " +
"\n\t时间:${DateUtil.nowDateTime}" +
"\n\t经度:${location.longitude},纬度:${location.latitude}" +
"\n\t高度:${location.altitude}米,精度:${location.accuracy}米" +
"\n\t地址:$address"
}

上述代码看起来显然简明扼要,寥寥数行便搞定了完整的功能实现。如果使用Java代码实现该功能,首先HTTP调用就得提供底层的接口访问代码,其次分线程请求网络又得专门写个继承自AsyncTask的任务处理代码,末了Activity这边厢还得实现该任务的完成事件,真是兴师动众、劳民伤财。由此可见Kotlin的网络交互是革命性的,方式虽然简单,却足以应付大部分的网络通信需求,并且运行效果与Java代码几无差别,例如调用地图接口查询地址信息,无论采用Java编码还是Kotlin编码,界面效果都如下图所示。

上面利用readText方法就完成了文本数据的接口调用,当时提到了readBytes可用于获取二进制数据如图片文件,那么获取网络图片是否也同样方便呢?下面我们继续探讨如何使用Kotlin代码读取网络图片。
获取网络图片的基本流程同文本格式的接口访问,一样先通过URL类构建HTTP对象,然后在doAsync代码块中调用HTTP对象的readBytes方法获得图片的字节数组。将字节数组转换为位图对象,这在前面的文章《Kotlin入门(27)文件读写操作》已经加以介绍,即利用BitmapFactory工具的decodeByteArray方法实现转换操作。转换好的位图当然可以在主线程直接显示出来,也可以先保存为图片文件,等到需要的时候再去读取。前面描述如何把位图保存为图片文件时,由于Bitmap相关类并未提供简单的图片保存方法,因此当时保存位图文件还着实颇费了一番功夫。现在保存网络图片反而无需如此折腾,这是因为获取网络图片得到了字节数组,字节数组保存为文件可是相当方便的噢,只要调用File对象的writeBytes方法,短短一行就保存好图片了。介绍完了网络图片的存取流程,最终的Kotlin编码一如既往地简单明了,下面展示了一个验证码动态显示的页面代码:

class HttpImageActivity : AppCompatActivity() {
private val imageUrl = "http://222.77.181.14/ValidateCode.aspx?r=" override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_http_image)
iv_image_code.setOnClickListener { getImageCode() }
getImageCode()
} //获取网络上的图片验证码
private fun getImageCode() {
iv_image_code.isEnabled = false
doAsync {
val url = "$imageUrl${DateUtil.getFormatTime()}"
val bytes = URL(url).readBytes()
//把字节数组解码为位图数据
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
//也可通过下面三行代码把字节数组写入文件,即生成一个图片文件
val path = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/"
val file_path = "$path${DateUtil.getFormatTime()}.png"
File(file_path).writeBytes(bytes)
//获得验证码图片数据,回到主线程把验证码显示在界面上
uiThread { finishGet(bitmap) }
}
} //在主线程中显示获得到的验证码图片
private fun finishGet(bitmap: Bitmap) {
iv_image_code.setImageBitmap(bitmap)
iv_image_code.isEnabled = true
}
}

看到了吧,即使是完整的Activity代码,Kotlin也只需数十行而已。倘若使用Java完成同样的功能,除了HTTP底层与AsyncTask的编码之外,还得补充Bitmap对象的图片保存代码。也就是说,Java代码需要额外添加三个工具类的实现代码,光光这一点,Kotlin的效率就令人赞叹。而且,短小精悍的Kotlin代码并未造成任何功能缺失,以上面的图片验证码页面为例,使用Java编码和使用Kotlin编码,最终的显示效果都如下图所示。

Kotlin入门(32)网络接口访问的更多相关文章

  1. Kotlin入门教程——目录索引

    Kotlin是谷歌官方认可的Android开发语言,Android Studio从3.0版本开始就内置了Kotlin,所以未来在App开发中Kotlin取代Java是大势所趋,就像当初Android ...

  2. Kotlin入门(28)Application单例化

    Application是Android的又一大组件,在App运行过程中,有且仅有一个Application对象贯穿应用的整个生命周期,所以适合在Application中保存应用运行时的全局变量.而开展 ...

  3. Kotlin入门(5)字符串及其格式化

    上一篇文章介绍了数组的声明和操作,包括字符串数组的用法.注意到Kotlin的字符串类也叫String,那么String在Java和Kotlin中的用法有哪些差异呢?这便是本文所要阐述的内容了. 首先要 ...

  4. Kotlin入门(11)江湖绝技之特殊函数

    上一篇文章介绍了Kotlin对函数的输入参数所做的增强之处,其实函数这块Kotlin还有好些重大改进,集中体现在几类特殊函数,比如泛型函数.内联函数.扩展函数.尾递归函数.高阶函数等等,因此本篇文章就 ...

  5. Kotlin入门(13)类成员的众生相

    上一篇文章介绍了类的简单定义及其构造方式,当时为了方便观察演示结果,在示例代码的构造函数中直接调用toast提示方法,但实际开发是不能这么干的.合理的做法是外部访问类的成员属性或者成员方法,从而获得处 ...

  6. Kotlin入门(14)继承的那些事儿

    上一篇文章介绍了类对成员的声明方式与使用过程,从而初步了解了类的成员及其运用.不过早在<Kotlin入门(12)类的概貌与构造>中,提到MainActivity继承自AppCompatAc ...

  7. Kotlin入门(15)独门秘笈之特殊类

    上一篇文章介绍了Kotlin的几种开放性修饰符,以及如何从基类派生出子类,其中提到了被abstract修饰的抽象类.除了与Java共有的抽象类,Kotlin还新增了好几种特殊类,这些特殊类分别适应不同 ...

  8. Asp.Net SignalR 使用记录 技术回炉重造-总纲 动态类型dynamic转换为特定类型T的方案 通过对象方法获取委托_C#反射获取委托_ .net core入门-跨域访问配置

    Asp.Net SignalR 使用记录   工作上遇到一个推送消息的功能的实现.本着面向百度编程的思想.网上百度了一大堆.主要的实现方式是原生的WebSocket,和SignalR,再次写一个关于A ...

  9. Kotlin 入门教程

    Kotlin 入门教程 Android / Java https://developer.android.com/kotlin?hl=zh-cn 使用 Kotlin 开发 Android 应用 使用 ...

随机推荐

  1. [Swift]LeetCode904. 水果成篮 | Fruit Into Baskets

    In a row of trees, the i-th tree produces fruit with type tree[i]. You start at any tree of your cho ...

  2. springmvc 请求参数解析细节

    springmvc 的请求流程,相信大家已经很熟悉了,不熟悉的同学可以参考下资料! 有了整体流程的概念,是否对其中的实现细节就很清楚呢?我觉得不一定,比如:单是参数解析这块,就是个大学问呢? 首先,我 ...

  3. 洛谷P2089烤鸡

    题目链接:https://www.luogu.org/problemnew/show/P2089 题目详情: 题目背景 猪猪hanke得到了一只鸡 题目描述 猪猪Hanke特别喜欢吃烤鸡(本是同畜牲, ...

  4. Spring中的IOC_源码_随笔

    Spring ioc 叫控制反转,也就是把创建Bean的动作交给Spring去完成. spring ioc  流程大致为 定位-> 加载->注册 先说几个比较有意思的点 1.Spring中 ...

  5. linux静态ip的设置

    我们经常使用虚拟机安装(我使用的linux版本是CentOS6.5),然后配置服务器的web环境,用于程序的调试.默认情况下,linux使用动态ip,每次启动linux时,它的ip地址都有可能发生变化 ...

  6. .NET Core实战项目之CMS 第八章 设计篇-内容管理极简设计全过程

    写在前面 上一篇文章中我带着大家进行了权限部分的极简设计,也仅仅是一个基本的权限设计.不过你完全可以基于这套权限系统设计你的更复杂的权限系统,当然更复杂的权限系统要根据你的业务来进行,因为任何脱离实际 ...

  7. redhat 6.5安装ansible

    安装epel 源: rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm 安装ansible ...

  8. How does the vuejs add the query and walk the object?

    让这个老实返回的页面添加特殊路由,这个页面常常都是登录注册.这次我们根据登录举例. 省略 { path:'/login?url=:url', name:'loginfirst', component: ...

  9. 『没有上司的舞会 树形DP』

    树形DP入门 有些时候,我们需要在树形结构上进行动态规划来求解最优解. 例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子 ...

  10. python转义字符——重点解释:\b,\n和\r区别

    放在最前面: 有时我们并不想让转义字符生效,我们只想显示字符串原来的意思,这就要用r和R来定义原始字符串.如:print r'\t\r' 实际输出为“\t\r”. 主要参考:AllenW的博客 转义字 ...