在Android中,使用Kotlin的 API請求簡易方法


原文標題:API request in Android the easy way using Kotlin

原文鏈接:http://antonioleiva.com/api-request-kotlin/

原文作者:Antonio Leiva(http://antonioleiva.com/about/

原文發布:2015-07-21

 

Kotlin是功能非常強大的編程語言,其目標是利用較少的模板(boilerplate)編寫更多的代碼。尤其是在Android開發中。除了編程語言自身和它的類之外,Kotlin還為已有的Java類提供一組好用的擴展。這個例子是請求API和下載結果的方法。

 

我知道已經有許多不同的庫可以幫助我們做這些工作,並且因Kotlin與Java的互用性,它也能使用這些庫。但是,我們有時候僅僅因為大的庫更簡單、不易出錯,對於小需求也用大庫。

 

API請求:Java 與 Kotlin對比

 

我總喜歡把這兩種語言進行對比,看看堅持使用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類提供了擴展函數,避免我們編寫所有代碼。前面的代碼可以轉換為:

 

1 val result = URL("<api call>").readText()

 

對於大量的響應,不建議使用這個函數,但是在大多數情況下,它是足夠了。如果不這樣,還有許多其他有趣的擴展函數,如:BufferedReader.forEachLine(),它產生行Sequence,讓我們用它們中任何一個一起做些事。或是,你可以通過BufferedReader.lineSequence()得到原始的Sequence<String>。這時,你能夠執行Sequence允許的不同轉換中的任何一種,如:過濾、排序、映射等等。

 

異步調用

 

如你所知,主線程是負責UI呈現和交互的,我們不應該因其它運行時間長的任務阻塞它,這將會影響UI性能。在HTTP請求情況下, Android SDK甚至通過拋出一個異常來阻止我們這么做。在Android典型的解決方案是使用AsyncTaskAsyncTask有一個doInBackground抽象方法,其在另個線程中執行。

 

除了讓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給出返回主線的機會。asyncContext的擴展函數實現,且使用它弱應用,所以不會阻止GC釋放內存。

 

uiThread優勢的方面是它依據使用類,以用不同的方式來實現。如果我們從Activity中調用它,假設actiivity.isFinishing()返回trueuiThread代碼是不會執行的,並且在此情況下不會崩潰。

 

假設你要用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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM