Kotlin入门(32)网络接口访问

手机上的资源毕竟有限,为了获取更丰富的信息,就获得辽阔的互联网大海上冲浪。对于App自身,也要常常与服务器交互,以便获取最新的数据显示到界面上。这个客户端与服务端之间的信息交互,基本使用HTTP协议进行通讯,即App访问服务器的HTTP接口来传输数据。HTTP接口调用在Java代码中可不是一个轻松的活,开发者若用最基础的HttpURLConnection来编码的话,至少要考虑如下场景的处理:
一、HTTP的请求方式是什么,是GET仍是POST仍是PUT仍是DELETE?
二、HTTP的链接超时时间是多少,请求应答的超时时间又是多少?
三、HTTP头部的语言和浏览器信息该设置为何?
四、HTTP传输的数据内容采起的是哪一种编码方式?
五、HTTP的应答数据若是是压缩过的,又要如何解压?
六、HTTP的输入输出流须要注意哪些方面?
七、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代码片断:java

    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编码,界面效果都以下图所示。git

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

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编码,最终的显示效果都以下图所示。后端

相关文章
相关标签/搜索