Retrieving data from API

8 Retrieving data from API

8.1 Performing a request

Our current placeholder texts are good to start feeling the idea of what we want to achieve, but now it’s time to request some real data, which will be used to populate the RecyclerView . We’ll be using OpenWeatherMap¹⁹ API to retrieve data, and some regular classes for the request. As Kotlin interoperability is extremely powerful, you could use any library you want, such as Retrofit²⁰ , for server requests. However, as we are just performing a simple API request, we can easily achieve our goal much easier without adding another third party library.

Besides, as you will see, Kotlin provides some extension functions that will make requests much simpler. First, we’re going to create a new Request class:

1 class Request ( val url: String) {

3 fun run () { 4 val forecastJsonStr = URL(url).readText() 5 Log.d(javaClass.simpleName, forecastJsonStr)

The constructor simply receives an url. Then the run function reads the result and outputs the json in the Logcat.

The implementation is really easy when using readText , an extension function from the Kotlin standard library. This method is not recommended for huge responses, but it will be good enough in our case.

¹⁹ http://openweathermap.org/ ²⁰ https://github.com/square/retrofit

37 If you compare this code with the one you’d need in Java, you will see we’ve saved

8 Retrieving data from API

a huge amount of overhead just using the standard library. An HttpURLConnection ,

a BufferedReader and an iteration over the result would have been necessary to get the same result, apart from having to manage the status of the connection and the reader. Obviously, that’s what the function is doing behind the scenes, but we have it for free.

In order to be able to perform the request, the App must use the Internet permission. So it must be added to the AndroidManifest.xml :

1 <uses-permission android:name= "android.permission.INTERNET" />

8.2 Performing the request out of the main thread

As you may know, HTTP requests are not allowed in the main thread, or the App will throw an exception. This is because blocking the UI thread is a really bad practice. The common solution in Android is to use an AsyncTask . But these classes are ugly and difficult to implement without any side effects. AsyncTask s are dangerous if not used carefully, because by the time it reaches postExecute the activity could have been destroyed, and the task will crash.

Anko provides a very easy DSL to deal with asynchrony, which will fit most basic needs. It basically provides a doAsync function that will execute its code in another thread, with the option to return to the main thread by calling uiThread . Executing the request in a secondary thread is as easy as this:

8 Retrieving data from API

1 val url = "http://api.openweathermap.org/data/2.5/forecast/daily?" + 2 "APPID=15646a06818f61f7b8d7823ca833e1ce&q=94043&mode=json&units=metri\ 3 c&cnt= 7 "

5 doAsync() { 6 Request(url).run() 7 uiThread { longToast( "Request performed" )}

You can get the url from the repository branch²¹ for this lesson.

A nice thing about uiThread is that it has a different implementations depending on the caller object. If it’s used by an Activity , the uiThread code won’t be executed if activity.isFinishing() returns true , and it won’t crash if the activity is no longer valid.

You also can use your own executor:

1 val executor = Executors.newScheduledThreadPool( 4 )

2 async(executor) { 3 // Some task 4 }

doAsync returns a java Future , in case you want to work with futures. And if you need it to return a future with a result, you can use doAsyncResult .