原文標題:API request in Android the easy way using Kotlinandroid
原文連接:http://antonioleiva.com/api-request-kotlin/git
原文做者:Antonio Leiva(http://antonioleiva.com/about/)github
原文發佈:2015-07-21編程
Kotlin是功能很是強大的編程語言,其目標是利用較少的模板(boilerplate)編寫更多的代碼。尤爲是在Android開發中。除了編程語言自身和它的類以外,Kotlin還爲已有的Java類提供一組好用的擴展。這個例子是請求API和下載結果的方法。api
我知道已經有許多不一樣的庫能夠幫助咱們作這些工做,而且因Kotlin與Java的互用性,它也能使用這些庫。可是,咱們有時候僅僅由於大的庫更簡單、不易出錯,對於小需求也用大庫。app
我總喜歡把這兩種語言進行對比,看看堅持使用Java咱們會錯過什麼。從URL恢復JSON的典型代碼是這樣:異步
1 try { 2 URL url = new URL("<api call>"); 3 4 urlConnection = (HttpURLConnection) url.openConnection(); 5 urlConnection.setRequestMethod("GET"); 6 urlConnection.connect(); 7 8 InputStream inputStream = urlConnection.getInputStream(); 9 StringBuffer buffer = new StringBuffer(); 10 if (inputStream == null) { 11 // Nothing to do. 12 return null; 13 } 14 reader = new BufferedReader(new InputStreamReader(inputStream)); 15 16 String line; 17 while ((line = reader.readLine()) != null) { 18 buffer.append(line + "\n"); 19 } 20 21 if (buffer.length() == 0) { 22 return null; 23 } 24 result = buffer.toString(); 25 } catch (IOException e) { 26 Log.e("Request", "Error ", e); 27 return null; 28 } finally{ 29 if (urlConnection != null) { 30 urlConnection.disconnect(); 31 } 32 if (reader != null) { 33 try { 34 reader.close(); 35 } catch (final IOException e) { 36 Log.e("Request", "Error closing stream", e); 37 } 38 } 39 }
Kotlin標準庫爲URL類提供了擴展函數,避免咱們編寫全部代碼。前面的代碼能夠轉換爲:async
1 val result = URL("<api call>").readText()
對於大量的響應,不建議使用這個函數,可是在大多數狀況下,它是足夠了。若是不這樣,還有許多其餘有趣的擴展函數,如:BufferedReader.forEachLine()
,它產生行Sequence
,讓咱們用它們中任何一個一塊兒作些事。或是,你能夠經過BufferedReader.lineSequence()
獲得原始的Sequence<String>
。這時,你可以執行Sequence
容許的不一樣轉換中的任何一種,如:過濾、排序、映射等等。編程語言
如你所知,主線程是負責UI呈現和交互的,咱們不該該因其它運行時間長的任務阻塞它,這將會影響UI性能。在HTTP請求狀況下, Android SDK甚至經過拋出一個異常來阻止咱們這麼作。在Android典型的解決方案是使用AsyncTask
。AsyncTask
有一個doInBackground
抽象方法,其在另個線程中執行。ide
除了讓AsyncTask
正常工做很難這一事實外,因爲它自身帶來了許多問題,使得經過它擴展建立一個新類、在onDestroy
中終止它等等,都是很乏味。這個(你可能須要更多的檢查以免崩潰)很是簡單的版本將是:
1 @Override protected void onCreate(Bundle savedInstanceState) { 2 super.onCreate(savedInstanceState); 3 4 task = new AsyncTask<Void, Void, String>() { 5 @Override protected String doInBackground(Void... params) { 6 return requestFromServer("<api call>"); 7 } 8 9 @Override protected void onPostExecute(String s) { 10 if (!isFinishing() && !isCancelled()) { 11 Log.d("Request", s); 12 Toast.makeText(ExampleActivity.this, "Request performed", Toast.LENGTH_LONG).show(); 13 } 14 } 15 }; 16 } 17 18 @Override protected void onDestroy() { 19 super.onDestroy(); 20 21 if (task != null) { 22 task.cancel(true); 23 task = null; 24 } 25 }
這實在不清晰也不直觀。當咱們在Android中用Kotlin開發時,咱們不能忘記Anko庫。它主要目的是提供DSL方式用代碼來建立佈局,而不是用XML。我實際使用過XML,因此我如今不使用它了,可是它仍是包括一整套很是有用的特性。特別對異步任務有些小的DSL。這樣在Kotlin中,前面的代碼可以減小爲:
1 async { 2 val result = URL("<api call>").readText() 3 uiThread { 4 Log.d("Request", result) 5 longToast("Request performed") 6 } 7 }
實際上,你有async
函數,它將在另外一個線程中執行代碼,並由uiThread
給出返回主線的機會。async
是Context
的擴展函數實現,且使用它弱應用,因此不會阻止GC釋放內存。
uiThread
優點的方面是它依據使用類,以用不一樣的方式來實現。若是咱們從Activity中調用它,假設actiivity.isFinishing()
返回true
,uiThread
代碼是不會執行的,而且在此狀況下不會崩潰。
假設你要用future,Async
返回Java Future
。若是你須要返回future結果,就能夠用asyncResult
。
你還可以用你本身的執行器:
1 val executor = Executors.newScheduledThreadPool(4) 2 async(executor) { 3 // Some task 4 }
用幾行代碼,咱們從一個很是典型的操做獲得相同(若是沒有更好的話)的結果,如:調用一個API,以String變量獲得結果。隱藏在這些擴展函數背後有許多有趣的代碼,因此我建議去重讀Kotlin和Anko源代碼,看看在幕後都作了什麼。
記住從我寫的書《Android開發者的Kotlin》中,你可以學習到Kotlin的這點以及許多其它能力,你將經過從0開始建立Android APP學習Kotlin。