Third Order of Business

Coding:

Go back to MainActivity.kt and declare the following variable at the top of the class:

private lateinit var llm: LinearLayoutManager

then within the onCreate() function, add these lines after the call to setContentView:

llm = LinearLayoutManager(this)

crypto_rv.layoutManager = llm

getCoins()

You may see some red lines under the crypto_rv declaration and Android Studio prompting you to import kotlinx.android.synthetic.main.activity_main.*; do so and it will go away.

For an in-depth explanation of what’s taking place, check out the official documentation (because, who doesn’t love documentation…right?…right?!).

The red lines under the getCoins() function call will prompt you to create the function, lets handle that now. Copy & paste the following:

fun getCoins(){



var client = OkHttpClient()

var apiUrl = "https://api.coinmarketcap.com/v1/ticker/?limit=10"

val request = Request.Builder().url(apiUrl).build()





client.newCall(request).enqueue(object: Callback {

override fun onFailure(call: Call?, e: IOException?) {

println("Failed"+e?.toString())

} override fun onResponse(call: Call?, response: Response?) {

val body = response?.body()?.string()

println("Body :"+body)

}



})



}

llm — Initialization of a LinearLayoutManager() which is required for a RecyclerView. It handles positioning item views and determines when to reuse ones that are no longer visible to the user.

client — declares and initializes an OkHttpClient().

apiUrl — holds the REST endpoint to query, with the “limit=10” parameter passed. This will list the top 10 coins.

request — takes in the url and returns an object (what ever the endpoint sends, in this case a JSONArray).

The client call must be done with enqueue to ensure that it does not occur on the Main UI Thread (more info on threading). Data is downloaded on a worker thread and gets called back after the response headers are ready, with either an HTTP response or a failure exception.

The onFailure() function will be triggered if an error occurred.

The onResponse() function returns the results (a JSONArray that the endpoint sends).

body — takes the result (JSONArray) and converts it to a string.

println(“Body :”+body) — will display the string, allowing us to see what variables the endpoint has.

Based on the println(check logcat), you should see an array of objects which look something like:

{

"id": "iota",

"name": "IOTA",

"symbol": "MIOTA",

"rank": "10",

"price_usd": "1.96153",

"price_btc": "0.00018221",

"24h_volume_usd": "64054500.0",

"market_cap_usd": "5452132036.0",

"available_supply": "2779530283.0",

"total_supply": "2779530283.0",

"max_supply": "2779530283.0",

"percent_change_1h": "-0.65",

"percent_change_24h": "3.12",

"percent_change_7d": "4.43",

"last_updated": "1519805951"

}

With this, we can select the variables to use in our Model object:

class CryptoModel (

val id: String,

val name: String,

val symbol: String,

val price_usd: String,

val percent_change_1h: String,

val percent_change_24h: String,

val percent_change_7d: String

)

Let’s make some adjustments to the onResponse() method:

val gson = Gson()

val cryptoCoins:List<CryptoModel> = gson.fromJson(body, object : TypeToken<List<CryptoModel>>() {}.type)



runOnUiThread {

crypto_rv.adapter = CryptoAdapter(cryptoCoins)

}

gson — an instance of Gson() (with its default configuration), we will use it to take the JSONArray, and deserialize it to a List of CryptoModel objects.

cryptoCoins — is the list of CryptoModel objects (which will be created by gson) mentioned above.

runOnUiThread — if you recall me mentioning the importance of using enqueue earlier (to not carry out a network task on the main thread)…Now that the network task is complete, we must return to the main thread with the data that was obtained, to pass into the last piece of the puzzle, the RecyclerView Adapter.

I’ve called my adapter CryptoAdapter.kt, and there are a few things to note:

It’s constructor, which takes in a list of CryptoModel objects.

CryptoAdapter(val cryptoCoins: List<CryptoModel>) The CryptoViewHolder class, which houses the items from the layout file we created earlier(crypto_layout.xml). The adapter’s onBindViewHolder() function which connects the the CryptoModel to the layout items.

Inside of the onBindViewHolder() function :

val coin = cryptoCoins.get(position) var imageUrl = "https://res.cloudinary.com/dxi90ksom/image/upload/"

holder?.coinName?.text = coin.name

holder?.coinSymbol?.text = coin.symbol

holder?.coinPrice?.text = coin.price_usd

holder?.oneHourChange?.text = coin.percent_change_1h+"%"

holder?.twentyFourHourChange?.text = coin.percent_change_24h+"%"

holder?.sevenDayChange?.text = coin.percent_change_7d+"%"

Picasso.with(holder?.itemView?.context).load(imageUrl+coin.symbol.toLowerCase()+".png").into(holder?.coinIcon)

imgUrl — the url endpoint for the crypto currency icons.

coin — A single CryptoModel object from the list.

holder — the CryptoViewHolder, and its widgets (textviews, imageviews).

Picasso —Image fetching and caching. It uses the imgUrl (which is concatenated with coinSymbol and .png extension) and places the retrieved image into the imageView.

That concludes this tutorial, hopefully it has helped someone perhaps learn the basics of sending HTTP requests and handling the response, or perhaps be the stepping stone for a full crypto currency tracker (feel free to leave a link to what you’ve made in the comments if you found this helpful).

Remember the full repo can be downloaded here.