手机上的资源毕竟有限,为了获取更丰富的信息,就得到辽阔的互联网大海上冲浪。对于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. 吴恩达机器学习笔记54-开发与评价一个异常检测系统及其与监督学习的对比(Developing and Evaluating an Anomaly Detection System and the Comparison to Supervised Learning)

    一.开发与评价一个异常检测系统 异常检测算法是一个非监督学习算法,意味着我们无法根据结果变量

  2. [Swift]LeetCode409. 最长回文串 | Longest Palindrome

    Given a string which consists of lowercase or uppercase letters, find the length of the longest pali ...

  3. [Swift]LeetCode643. 子数组最大平均数 I | Maximum Average Subarray I

    Given an array consisting of n integers, find the contiguous subarray of given length k that has the ...

  4. [Swift]LeetCode672. 灯泡开关 Ⅱ | Bulb Switcher II

    There is a room with n lights which are turned on initially and 4 buttons on the wall. After perform ...

  5. [Swift]LeetCode767. 重构字符串 | Reorganize String

    Given a string S, check if the letters can be rearranged so that two characters that are adjacent to ...

  6. Hystrix概念设计

    1. Hystrix概念设计 1.1. 大纲 1.2. 基本的容错模式 1.3. 断路器模式 1.4. 舱壁隔离模式 1.5. 容错理念 凡事依赖都可能失败 凡事资源都有限制 网络并不可靠 延迟是应用 ...

  7. SpringBoot 集成Mybatis 连接Mysql数据库

    记录SpringBoot 集成Mybatis 连接数据库 防止后面忘记 1.添加Mybatis和Mysql依赖 <dependency> <groupId>org.mybati ...

  8. JVM基础系列第6讲:Java 虚拟机内存结构

    看到这里,我相信大家对于一个 Java 源文件是如何变成字节码文件,以及字节码文件的含义已经非常清楚了.那么接下来就是让 Java 虚拟机运行字节码文件,从而得出我们最终想要的结果了.在这个过程中,J ...

  9. Linux(2)---记录一次线上服务 CPU 100%的排查过程

    Linux(2)---记录一次线上服务 CPU 100%的排查过程 当时产生CPU飙升接近100%的原因是因为项目中的websocket时时断开又重连导致CPU飙升接近100% .如何排查的呢 是通过 ...

  10. Quartz.NET学习笔记(二) Job和JobDetails

    Job和JobDetails的关系 接一篇的例子 ISchedulerFactory schedFact = new StdSchedulerFactory(); IScheduler sched = ...