Categories
Tutorials Android Kotlin

Rest API Client in Android using Volley and Gson

Making Http Request in android is very common when it comes to create a Restful API Client Application. Because this is a network call so it is very common that this task is kind of blocking call. When the API becomes more complex like when it needs to authenticate via OAuth2.0 or something, then the total Http call became a total mess. Thanks to prebuilt libraries like Volley which makes developers life easier and take all mess out of the code. 

Quote Master API based Applicaiton

In today post we are going to create an Application which fetch famous quotes from Rest API and display in a Recycler view. We use Volley and Gson for making Http request and parsing response Json data respectively. 

Let’s summarise today’s goals first

  • Create a recyclerview 
  • User volley to make Http Get request
  • Pass header parameters
  • Parse JSON Response into Model Class of quotes using Gson library
  • Put list of quotes into Recyclerview and display
  • Two buttons for Sharing Quote and one for Copying Quote text to clipboard 

Gradle imports

Once we had decided which libraries we are gonna use lets first add required gradle imports in app level gradle file 

implementation 'com.android.volley:volley:1.1.1'
implementation 'com.google.code.gson:gson:2.8.5'

Create API Key 

We are going to use Free Quote API from Mashape the biggest market place for free as well as private APIs. Create a free account and create and Generate API Key. 

Random Famous Quotes API from andrux

Once you create your account and open up above mentioned api then you will see your dashboard and click on get API Key button then on left panel you will see the example response of API data. 

Json Response of single Object



Creating Model Data Class in Kotlin

As you can see this response is very simple which contains just three variables “quotes”, “author” and “category” field. So according to above data we create a Model Data Class under model package folder. Let’s Create as follows 

data class Quote(var quote:String,var author:String,var category:String) 

Creating Recycler View

Now that we are ready to fetch data from API, but before that  we need to create our view where we can display fetched data. For this, We are going to use recyclerview. Let’s add recyclerview in our MainActiviy Layout xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
android:orientation="vertical"
android:background="#DDDDDD"
>


<android.support.v7.widget.RecyclerView
  android:id="@+id/recView1"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  app:layoutManager="android.support.v7.widget.LinearLayoutManager"
>

</android.support.v7.widget.RecyclerView>

</LinearLayout>

Creating Adapter Class

Next step for Recyclerview is to create it’s single Item resource layout file and an Adapter class. So let’s create Item.xml file in resource layout folder like this

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="#FFF"
>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>



<TextView
android:id="@+id/quote_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="some random quote , this is dummy text"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Large"
/>

<TextView
android:id="@+id/tvAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="4dp"
android:text="-Author"
/>
</LinearLayout>


<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#DEDEDE"
android:layout_marginTop="4dp"
/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="4dp"
>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:id="@+id/shareIntentButton"
android:padding="4dp"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Share"
android:drawableLeft="@drawable/ic_share_black_24dp"
android:textSize="24dp"
android:drawablePadding="2dp"
android:textStyle="bold"
/>

</LinearLayout>
<View
android:layout_width="2dp"
android:layout_height="match_parent"
android:background="#DEDEDE"
/>
<LinearLayout
android:id="@+id/markIntentButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:padding="4dp"
>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Copy"
android:drawableLeft="@drawable/ic_content_copy_black_24dp"
android:textSize="24dp"
android:drawablePadding="2dp"
android:textStyle="bold"
/>

</LinearLayout>



</LinearLayout>
</LinearLayout>

It will look like this 

Single Item layout file

Now create a new class inherited from Recyclerview.Adapter class

package com.fypsolutions.quotemaster

import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import com.fypsolutions.quotemaster.interactions.ItemInteractor
import com.fypsolutions.quotemaster.models.Quote

class QuoteAdapter(private val itemList:ArrayList<Quote>, private val interactorIntrface:ItemInteractor?): RecyclerView.Adapter<QuoteAdapter.ViewHolder>() {



override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.list_item, parent, false)
return ViewHolder(view)
}

override fun getItemCount(): Int {
return itemList.count()
}

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

holder.mTitleTView.text = itemList[position].quote
holder.mAuthor.text = itemList[position].author
holder.mBookMarkButton.setOnClickListener {
interactorIntrface?.onCopyText(itemList[position])
}
holder.mShareButton.setOnClickListener {
interactorIntrface?.onShareButonClick(itemList[position])
}
}


inner class ViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
val mTitleTView: TextView = mView.findViewById<View>(R.id.quote_text) as TextView
val mAuthor: TextView = mView.findViewById<View>(R.id.tvAuthor) as TextView
val mBookMarkButton:LinearLayout = mView.findViewById<View>(R.id.markIntentButton) as LinearLayout
val mShareButton:LinearLayout=mView.findViewById<View>(R.id.shareIntentButton) as LinearLayout

override fun toString(): String {
return super.toString() + " '" + mTitleTView.text + "'"+mAuthor.text+";"
}
}
}

Finally come back to your Main Activity class and just setup your recyclerview like this

Recyclerview setup in main activity

Next create some global variables for your API Call 

private val TAG = this.javaClass.simpleName
private val API_KEY = "Your-API-Key"
private val API_URL = "https://andruxnet-random-famous-quotes.p.mashape.com"
var gson = Gson()
var requestQueue:RequestQueue? = null
var stringRequest: StringRequest? = null

Here you can see that we created one variable for API-KEY and one for API_URL and one gson object and two objects from volley

Make Http Get Request using Volley

Now that we had set up every thing so final step is to make Get Request using volley library and parse response data using gson and then finally parse objects to global quote list and notify adapter about the change in data like this


val totalURL = String.format(API_URL+"?cat=%1\$s&count=%2\$s",
"famous",
10)
// Instantiate the RequestQueue.
val requestQueue = Volley.newRequestQueue(this)
stringRequest = object : StringRequest(Request.Method.GET, totalURL,
Response.Listener { response ->
val precount = quoteList.count()

val quoteJsonArray = JSONArray(response)
for (i in 0 until quoteJsonArray.length()) {
val singleObject = quoteJsonArray.getJSONObject(i)
val gsonparse = gson.fromJson(singleObject.toString(), Quote::class.java)
quoteList.add(gsonparse)


}

if(quoteJsonArray.length()>0){
mAdapter.notifyItemRangeChanged(precount,quoteList.count())


}

tvStatus.text="Length = ${quoteJsonArray.length()}"
},
Response.ErrorListener { error ->
tvStatus.text = error.toString()
Log.d("ERROR", "error => " + error.toString())
}
) {
@Throws(AuthFailureError::class)
override fun getHeaders(): Map<String, String> {
val params = HashMap<String, String>()
params["X-Mashape-Key"] = API_KEY
params["Accept"] = "application/json"
return params
}
}



// Add the request to the RequestQueue.
requestQueue?.add(stringRequest)

One more thing that we can do is to stop requestQueue in onStop method like this 

override fun onStop() {
super.onStop()
requestQueue?.cancelAll(TAG)
}

Handling Click Listners

As you may already noticed that we had some errors in our adapter class as we had not defined the interaction listener class to handle our click listeners so let’s just create an Interface first

interface  ItemInteractor{
fun onShareButonClick(quote: Quote)
fun onCopyText(quote: Quote)
}

This interface hold just two buttons click capturing functions, one for Share button click and one for Copying text to clipboard. Let’s quickly let implement MainActivity class this interface and provide methods there

class MainActivity : AppCompatActivity(), ItemInteractor {
override fun onCopyText(quote: Quote) {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(quote.author, quote.quote)
clipboard.primaryClip = clip
toast("Quote Copied to Clipboard")
}

override fun onShareButonClick(quote: Quote) {
val sendIntent = Intent()
sendIntent.action = Intent.ACTION_SEND
sendIntent.putExtra(Intent.EXTRA_TEXT,
quote.quote)
sendIntent.type = "text/plain"
startActivity(sendIntent)
}

}

Time to view real magic done on emulator or on real device which ever way you like so let’s quickly run the project and see things happening. 

Application Running Screenshot on Emulator
Application Screenshot

That’s it for today. Hope you enjoyed building app with me. Let me know if you face any problem in comments section, I will be happy to help 🙂

Download Full Source code

If you are curious to directly jump into full code? here is the link to github repository for this project files

By Abdul Rehman

My name is Abdul Rehman and I love to do Reasearch in Embedded Systems, Artificial Intelligence, Computer Vision and Engineering related fields. With 10+ years of experience in Research and Development field in Embedded systems I touched lot of technologies including Web development, and Mobile Application development. Now with the help of Social Presence, I like to share my knowledge and to document everything I learned and still learning.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.