How to use API connection with Kotlin Coroutines + Volley
When start developing API with Volley in Kotlin, you want to use Kotlin Coroutine instead of AsyncTask. We see how to use API connection using Volley and Coroutine as an example.
First of all, How can I take advantage of coroutines so I can write my code in concise manner:
Here's an example to Coroutine calling API Android
NetworkUtility.kt
MainViewModel.kt
MainActivity.kt
activity_main.xml
UserRVAdapter.kt
ly_item_user.xml
Best reference : API connection with Volley + Coroutine
When start developing API with Volley in Kotlin, you want to use Kotlin Coroutine instead of AsyncTask. We see how to use API connection using Volley and Coroutine as an example.
First of all, How can I take advantage of coroutines so I can write my code in concise manner:
Here's an example to Coroutine calling API Android
Volley overview
Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster. Volley is available on GitHub. Volley is an HTTP client developed by google for android development. You can use suspendCancellableCoroutine to make the Volley API request.NetworkUtility.kt
package com.example.myapplication
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import kotlinx.coroutines.suspendCancellableCoroutine
import org.json.JSONObject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
class NetworkUtility {
companion object {
val mRequestQueue: RequestQueue by lazy {
Volley.newRequestQueue(MainApp.get())
}
suspend fun APIrequest(url: String): JSONObject {
return suspendCancellableCoroutine { continuation ->
try {
// Sucess Listner
val success = Response.Listener<JSONObject> { response ->
if (continuation.isActive) {
continuation.resume(response)
}
}
// Error Listner
val error = Response.ErrorListener { error ->
if (continuation.isActive) {
continuation.resume(JSONObject())
}
}
val jsonObjectRequest =
JsonObjectRequest(Request.Method.GET, url, null, success, error)
mRequestQueue.add(jsonObjectRequest)
} catch (e: Exception) {
e.printStackTrace()
if (continuation.isActive) {
if (continuation.isActive) {
continuation.resumeWithException(e)
}
}
}
}
}
}
}
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import kotlinx.coroutines.suspendCancellableCoroutine
import org.json.JSONObject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
class NetworkUtility {
companion object {
val mRequestQueue: RequestQueue by lazy {
Volley.newRequestQueue(MainApp.get())
}
suspend fun APIrequest(url: String): JSONObject {
return suspendCancellableCoroutine { continuation ->
try {
// Sucess Listner
val success = Response.Listener<JSONObject> { response ->
if (continuation.isActive) {
continuation.resume(response)
}
}
// Error Listner
val error = Response.ErrorListener { error ->
if (continuation.isActive) {
continuation.resume(JSONObject())
}
}
val jsonObjectRequest =
JsonObjectRequest(Request.Method.GET, url, null, success, error)
mRequestQueue.add(jsonObjectRequest)
} catch (e: Exception) {
e.printStackTrace()
if (continuation.isActive) {
if (continuation.isActive) {
continuation.resumeWithException(e)
}
}
}
}
}
}
}
MainViewModel.kt
package com.example.myapplication
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
class MainViewModel : ViewModel() {
var usersList: MutableLiveData<ArrayList<User>> = MutableLiveData(arrayListOf())
var isLoadingData = true
var showProgress = MutableLiveData<Boolean>()
fun getData(urlStr: String) {
showProgress.value = true
viewModelScope.launch(Dispatchers.IO) {
val rss = NetworkUtility.APIrequest(urlStr)
withContext(Dispatchers.Main) {
// call to UI thread
isLoadingData = false
showProgress.value = false
usersList.value?.addAll(parseJsonString(rss.toString()))
}
}
}
fun parseJsonString(str: String): ArrayList<User> {
val jsonOb = JSONObject(str)
val list: ArrayList<User> = arrayListOf()
val jsonArray = jsonOb.getJSONArray("data");
for (j in 0..jsonArray.length() - 1) {
val user = User(
jsonArray.getJSONObject(j).getString("id"),
jsonArray.getJSONObject(j).getString("email"),
jsonArray.getJSONObject(j).getString("first_name"),
jsonArray.getJSONObject(j).getString("last_name"),
jsonArray.getJSONObject(j).getString("avatar")
)
list.add(user)
}
return list
}
}
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
class MainViewModel : ViewModel() {
var usersList: MutableLiveData<ArrayList<User>> = MutableLiveData(arrayListOf())
var isLoadingData = true
var showProgress = MutableLiveData<Boolean>()
fun getData(urlStr: String) {
showProgress.value = true
viewModelScope.launch(Dispatchers.IO) {
val rss = NetworkUtility.APIrequest(urlStr)
withContext(Dispatchers.Main) {
// call to UI thread
isLoadingData = false
showProgress.value = false
usersList.value?.addAll(parseJsonString(rss.toString()))
}
}
}
fun parseJsonString(str: String): ArrayList<User> {
val jsonOb = JSONObject(str)
val list: ArrayList<User> = arrayListOf()
val jsonArray = jsonOb.getJSONArray("data");
for (j in 0..jsonArray.length() - 1) {
val user = User(
jsonArray.getJSONObject(j).getString("id"),
jsonArray.getJSONObject(j).getString("email"),
jsonArray.getJSONObject(j).getString("first_name"),
jsonArray.getJSONObject(j).getString("last_name"),
jsonArray.getJSONObject(j).getString("avatar")
)
list.add(user)
}
return list
}
}
MainActivity.kt
package com.example.myapplication
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplication.databinding.ActivityMainBinding
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.toolbar.*
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
lateinit var userAdapter: UserRVAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
setSupportActionBar(toolbar)
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true)
viewModel = ViewModelProviders.of(this)[MainViewModel::class.java]
binding.mainVM = viewModel
binding.setLifecycleOwner(this)
viewModel.getData("https://reqres.in/api/users?page=1&per_page=12")
viewModel.showProgress.observe(this, Observer {
if (it == true) {
progressBar.visibility = View.VISIBLE
} else {
progressBar.visibility = View.GONE
}
})
viewModel.usersList.observe(this, Observer {
Log.e("ResSize", "" + it.size + "::" + it)
userAdapter.addList(it)
})
// Creates a vertical Layout Manager
rv_users.layoutManager = LinearLayoutManager(this)
userAdapter = UserRVAdapter(this)
rv_users.adapter = userAdapter
}
}
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.myapplication.databinding.ActivityMainBinding
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.toolbar.*
class MainActivity : AppCompatActivity() {
lateinit var viewModel: MainViewModel
lateinit var userAdapter: UserRVAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
setSupportActionBar(toolbar)
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true)
viewModel = ViewModelProviders.of(this)[MainViewModel::class.java]
binding.mainVM = viewModel
binding.setLifecycleOwner(this)
viewModel.getData("https://reqres.in/api/users?page=1&per_page=12")
viewModel.showProgress.observe(this, Observer {
if (it == true) {
progressBar.visibility = View.VISIBLE
} else {
progressBar.visibility = View.GONE
}
})
viewModel.usersList.observe(this, Observer {
Log.e("ResSize", "" + it.size + "::" + it)
userAdapter.addList(it)
})
// Creates a vertical Layout Manager
rv_users.layoutManager = LinearLayoutManager(this)
userAdapter = UserRVAdapter(this)
rv_users.adapter = userAdapter
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<data>
<variable name="mainVM" type="com.example.myapplication.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
tools:context=".MainActivity">
<include layout="@layout/toolbar" />
<TextView
app:layout_constraintTop_toBottomOf="@+id/toolbar"
android:id="@+id/tv_select_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Users"
android:layout_margin="7dp"
android:textColor="@android:color/black"
app:layout_constraintLeft_toLeftOf="parent"
android:textSize="20sp"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/tv_select_user"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/rv_users"
android:layout_width="match_parent"
android:layout_height="0dp"/>
<ProgressBar
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:id="@+id/progressBar"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
<layout 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">
<data>
<variable name="mainVM" type="com.example.myapplication.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
tools:context=".MainActivity">
<include layout="@layout/toolbar" />
<TextView
app:layout_constraintTop_toBottomOf="@+id/toolbar"
android:id="@+id/tv_select_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Users"
android:layout_margin="7dp"
android:textColor="@android:color/black"
app:layout_constraintLeft_toLeftOf="parent"
android:textSize="20sp"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/tv_select_user"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/rv_users"
android:layout_width="match_parent"
android:layout_height="0dp"/>
<ProgressBar
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:id="@+id/progressBar"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
UserRVAdapter.kt
package com.example.myapplication
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.ly_item_user.view.*
class UserRVAdapter(val context: Context): RecyclerView.Adapter<UserRVAdapter.ViewHolder>() {
var items : ArrayList<User> = arrayListOf()
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val posObj=items.get(position);
holder.tv_name1?.text =posObj.first_name +" "+posObj.last_name
holder.tv_email1?.text = posObj.email
GlideApp.with(holder.iv_profile1.context)
.load(posObj.avatar)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.apply(RequestOptions.circleCropTransform())
.error(R.drawable.ic_launcher_background)
.placeholder(R.drawable.ic_launcher_background)
.into(holder.iv_profile1)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.ly_item_user, parent, false))
}
fun addList(itemsNew : ArrayList<User>){
this.items=itemsNew
notifyDataSetChanged()
Log.e("ResSize:ItemsIF", "" + items.size)
}
override fun getItemCount(): Int {
return items.size
}
class ViewHolder (view: View) : RecyclerView.ViewHolder(view) {
// Holds the TextView that will add each animal to
val tv_name1 = view.tv_name
val tv_email1 = view.tv_email
val iv_profile1 = view.iv_profile
}
}ly_item_user.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_profile"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="50dp"
android:layout_margin="10dp"
android:layout_height="50dp"/>
<TextView
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toRightOf="@id/iv_profile"
app:layout_constraintBottom_toTopOf="@+id/tv_email"
android:id="@+id/tv_name"
android:textSize="20sp"
android:text="Pradip"
android:layout_marginLeft="10dp"
android:textColor="@android:color/black"
app:layout_constraintVertical_chainStyle="packed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_marginLeft="10dp"
app:layout_constraintLeft_toRightOf="@id/iv_profile"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_name"
android:id="@+id/tv_email"
android:text="Tilala"
android:textColor="@android:color/darker_gray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<View
app:layout_constraintTop_toBottomOf="@id/iv_profile"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:background="#f3f3f3"
android:layout_margin="10dp"
android:layout_height="2dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Best reference : API connection with Volley + Coroutine
No comments:
Post a Comment