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編碼,最終的顯示效果都以下圖所示。後端

相關文章
相關標籤/搜索