Sending Network Request using Kotlin

Networking has always been necessary in any app. So I decided to write about doing network calls using Kotlin. So let’s start by setting up the project.

I am using Android Studio 3.0 for this tutorial, so if you want to follow along you’ll want to have that as well.
Create a new project and tick on Include Kotlin support.

Now before doing anything else, let’s setup our dependencies that we’re going to use in our project. For Networking I am going to use Fuel. Its a Networking library written completely in Kotlin, and for parsing JSON into object model, I am going to use Klaxon. I am also going to add dependencies for using Recycler View and CardView. By the end of this tutorial, we’ll be able to understand how to do a basic network request. We’re going to use this Placeholder API for that purpose.

Dependencies

 compile 'com.github.kittinunf.fuel:fuel-android:1.10.0'
 compile 'com.beust:klaxon:0.30'
 implementation 'com.android.support:cardview-v7:26.1.0'
 implementation 'com.android.support:recyclerview-v7:26.1.0'

After that add internet permission in your AndroidManifest.xml

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

Views

It’s time we start creating our layouts. In your layout folder, create a layout called recycler_view_row.xml. Which is going to represent single row of the list. Paste the following code inside your newly created xml.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardCornerRadius="4dp"
        android:layout_margin="5dp"
        >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            >

            <TextView
                android:id="@+id/title_text_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Title"
                android:gravity="center"
                android:textAlignment="center"
                android:textSize="16sp"
                android:textStyle="bold" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="Body"
            android:id="@+id/body_text_view"
            />
        </LinearLayout>

    </android.support.v7.widget.CardView>
</LinearLayout>

Now in your activity_main.xml, do the following.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.kodesnippets.aaqibhussain.kotlinfuel.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:id="@+id/recycler_view"
         >
    </android.support.v7.widget.RecyclerView>
</RelativeLayout>

Model

There are two things we need to create, an Adapter for the RecyclerView and the Model which will help us populate the adapter.
Basically our JSON which we are fetching from the server consists of array of JSONObjects. Inside each JSONObject contains keys; id, userId, body and title. So our model will be quite simple.

Create a class and name it PostModel.

package com.kodesnippets.aaqibhussain.kotlinfuel

import com.beust.klaxon.JsonObject
import com.beust.klaxon.int
import com.beust.klaxon.string

/**
 * Created by aaqibhussain on 24/9/17.
 */class PostModel  {

    var id : Int? = null
    var userId : Int? = null
    var body : String? = null
    var title : String? = null

    constructor(jsonObject: JsonObject){

        id = jsonObject.int("id")
        userId = jsonObject.int("userId")
        body = jsonObject.string("body")
        title = jsonObject.string("title")
    }

}

Create another class and name it PostAdapter.

package com.kodesnippets.aaqibhussain.kotlinfuel

import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView


/**
 * Created by aaqibhussain on 24/9/17.
 */class PostAdapter(dataSet: List<PostModel>) : RecyclerView.Adapter<PostAdapter.ViewHolder>(){

    val dataSet : List<PostModel> = dataSet
    final var onClick : (View)-> Unit = {}

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
        val titleTextView = view.findViewById<TextView>(R.id.title_text_view) as TextView
        val bodyTextView = view.findViewById<TextView>(R.id.body_text_view) as TextView

    }

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {

        val view = LayoutInflater.from(parent!!.context).inflate(R.layout.recycler_view_row, parent,false)

        view.setOnClickListener(View.OnClickListener { view ->
            this.onClick(view)
        })
        return ViewHolder(view)

    }

    override fun onBindViewHolder(holder: ViewHolder?, position: Int) {

        holder?.let { holder ->
            holder.titleTextView.text = this.dataSet[position].title
            holder.bodyTextView.text = this.dataSet[position].body
        }

    }


    override fun getItemCount(): Int {

        return  this.dataSet.size
    }

}

In your MainActivity, create the following variables.

 lateinit var recyclerView : RecyclerView
 lateinit var recycletViewAdapter : RecyclerView.Adapter<PostAdapter.ViewHolder>
 lateinit var recyclerViewLayoutManager : RecyclerView.LayoutManager
 var adapter: PostAdapter? = null

After that we’ll setup our RecyclerView in onCreate.

 fun setupViews(){

        recyclerView = findViewById(R.id.recycler_view)
        recyclerViewLayoutManager = LinearLayoutManager(applicationContext)
        recyclerView.layoutManager = recyclerViewLayoutManager

    }

and for fetching the JSON, I have written a generic function.

 fun getRequest(url: String, success: (String) -> Unit, failure: (FuelError) -> Unit) {

        Fuel.get(url).responseString() { request, response, result ->

            val (data, error) = result
            if (error != null) {
                Log.v("Error", error!!.toString())
                failure(error)
            } else {
                val onSuccess = data ?: return@responseString
                success(onSuccess)

            }

        }
    }

How to use this function? It’s pretty straight forward. Just provide a URL and it’ll return you a JSON string or an error respectively.

  fun getData(){
        val posts = "https://jsonplaceholder.typicode.com/posts"
        getRequest(posts,success = { response ->

            val parser = Parser()
            val stringBuilder = StringBuilder(response)
            val model =  parser.parse(stringBuilder) as JsonArray<JsonObject>
            val postModel  = model.map { PostModel(it)}.filterNotNull()
           
            this.adapter = PostAdapter(postModel)
            recycletViewAdapter = adapter!!
            recyclerView.adapter = recycletViewAdapter
            recycletViewAdapter.notifyDataSetChanged()
            adapter?.onClick = { view ->

                val itemPosition = recyclerView.getChildLayoutPosition(view)
                Log.d("ITEM:POSITION",postModel[itemPosition].body)
            }

            Log.d("code",postModel.first().body)
            Log.d("Mapped::",postModel.first().title)
            Log.d("dode",postModel.first().userId.toString())
            Log.d("Mapped::",postModel.first().id.toString())

        },failure ={ error ->

        } )


    }

I will explain the above code a little bit. What it does is that when you get the response string, we create a string builder and pass it to the Parser class object’s function parse, provided by the Klaxon library which easily cast it to JsonArray of JsonObjects, which we can cast into our model class object which is PostModel, that’s what is being done here using the .map lambda function of the JsonArray, after the mapping of objects a function named filterNotNull() is called so that all the objects which are not null can be filtered out in an array, which can then be further passed into the adapter.

NOTE: if you use the default Java classes of JSONObject and JSONArray, you won’t be able to use functions like map, flatMap, or filterNotNull. 

After everything is done, call both of the functions in your onCreate. It should look something like this.

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        setupViews()
        getData()

    }

Now run your app and see the magic. You might get the result similar to the following screenshot.

So that’s all for this tutorial. Hope you guys liked it.
You can find the complete source code for this tutorial here.

Adiós!

 

Aaqib Hussain

Aaqib is an enthusiastic programmer with the love of Swift and anything that looks like Swift i.e Kotlin. He loves writing code in Swift, and exploring new technology and platforms. He likes to listen to old music. When he is not writing code, he's probably spend his time watching movies, tv-shows or anime, or either doing some research for writing the next article. He started Kode Snippets in 2015.

View Comments

Recent Posts

Things to know when moving to Germany

This article covers some important things you must know when you are considering a move…

3 years ago

Unit Testing in Android for Dummies

What is Unit Testing? In its simplest term, unit testing is testing a small piece…

4 years ago

Factory Design Pattern

In this article, you will learn about a type of Creational Design Pattern which is…

5 years ago

Creating Target specific Theme in iOS

In this tutorial, you will go through the use of targets to achieve two separate…

5 years ago

Facade Design Pattern

In this article, you will learn about a type of Structural Design Pattern which is…

5 years ago

Singleton Design Pattern

In this article you will learn about a type of Creational Design Pattern which is…

5 years ago