Load and parse JSON and show loaded employees data in a RecyclerView

L

This tutorial teaches how to load JSON data from the web and show loaded data in a RecyclerView. You should already have a basic knowledge how to use threads, how to use images and loading JSON from web. Application will show all employees in a list and detailed information in different activity.

JSON Data

Mockaroo lets you generate up to 1,000 rows of realistic test data in CSV, JSON, SQL, and Excel formats. Use Mockaroo service and generate a JSON data structure, which includes employee’s data. Save it to your server (look below picture). If you don’t have any server or you have some problems to generate JSON data, you can use https://ptm.fi/data/android_employees.json data. You should try to create your own file. Save it for example to https://jsonbin.io/.

There is employees key, which points to array of employees in JSON file. You might need to modify your generated JSON file.

Images will be loaded from https://randomuser.me service and regular expression will be used to get random images. Use following formula in image field https://randomuser.me/api/portraits/(wo)?{0,1}men/\d{1,2}.jpg

Use same Field Names what are visible at the below picture.

Create a new project

  • Create a new project and name it to “EmployeesApp”, include Kotlin support
  • Set Phone and Tablet target and select newest API
  • Use Empty Activity template
  • Configure Activity as default settings

Use Volley to load JSON

Open the build.gradle file for your app module and add Volley library to the dependencies section. Remember check the newest version number from Android developer site.

implementation 'com.android.volley:volley:1.1.1'

Add RecyclerView to your layout

Add the RecyclerView to MainActivity layout file. Just drag and drop RecyclerView to your main layout. Remember add layout constraints and give and id recyclerView.

Following layout uses RecyclerViewas the only view for the whole layout. Remember add an id recyclerView to your RecyclerView element.

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Allow internet permission in manifest

Remember add internet permission to your application manifest file and android:usesCleartextTraffic="true" attribute to Application element in manifest to allow data loading from HTTP, if you are using HTTP.

Programming

MainActivity

Employees JSON data can be loaded, when application is launched. Modify your MainActivity’s onCreate method to load JSON data with Volley. You need to create a JsonObjectRequest object with Listener and ErrorListener situations. If everything goes fine, loaded JSON data can be parsed in Response.Listener.

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

  // Instantiate the RequestQueue
  val queue = Volley.newRequestQueue(this)
  // URL to JSON data - remember use your own data here
  val url = "https://YOUR.DOMAIN/employees.json"
  // Create request and listeners
  val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
    Response.Listener { response ->
      // Get employees from JSON
      val employees = response.getJSONArray("employees")
      Log.d("JSON",employees.toString())
    },
    Response.ErrorListener { error ->
      Log.d("JSON",error.toString())
    }
  )
  // Add the request to the RequestQueue.
  queue.add(jsonObjectRequest)
}   

Run and test

Run your application and you should see Log-message in your LogCat window in Android Studio.

2019-12-28 14:58:03.398 15467-15467/fi.ptm.employeesapp D/JSON: [{"id":1,"firstName":"Violante","lastName":"Longhi","email":"vlonghi0@wikispaces.com","phone":"633-736-5682","title":"Structural Analysis Engineer","department":"Training","image":"https:\/\/randomuser.me\/api\/portraits\/med\/men\/8.jpg"},{"id":2,"firstName":"Godfry","lastName":"Lyffe","email":"glyffe1@cafepress.com","phone":"229-629-9209","title":"Marketing Assistant","department":"Business Development","image":"https:\/\/randomuser.me\/api\/portraits\/med\/women\/93.jpg"},{"id":3,"firstName":"Roselle","lastName":"Scaysbrook",...

Connect data to RecyclerView

Once you have added a RecyclerView to your layout, you can connect it to a layout manager, and attach an adapter for the data to be displayed. All this can be done in MainActivity at the same time when a JSON data will be loaded. EmployeesAdapter will be created later in this exercise.

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

  // Use LinearManager as a layout manager for recyclerView
  recyclerView.layoutManager = LinearLayoutManager(this)

  // Instantiate the RequestQueue
  val queue = Volley.newRequestQueue(this)
  // URL to JSON data - remember use your own data here
  val url = "https://YOUR.DOMAIN/employees.json"
  // Create request and listeners
  val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
    Response.Listener { response ->
      // Get employees from JSON
      val employees = response.getJSONArray("employees")
      // Create Employees Adapter with employees data
      recyclerView.adapter = EmployeesAdapter(employees)
    },
    Response.ErrorListener { error ->
      Log.d("JSON",error.toString())
    }
  )
  // Add the request to the RequestQueue.
  queue.add(jsonObjectRequest)
}

Add an adapter

Create a new Kotlin class file and name it to EmployeesAdapter. To feed all your data to the RecyclerView, you must extend adapter from the RecyclerView.Adapter class. This object creates views for items, and replaces the content of the views with new data items when the original item is no longer visible.

// Employees Adapter, used in RecyclerView in MainActivity
class EmployeesAdapter(private val employees: JSONArray) 
  : RecyclerView.Adapter<EmployeesAdapter.ViewHolder>() {
}

The layout manager calls the adapter’s onCreateViewHolder() method. This method needs to construct a RecyclerView.ViewHolder and set the view it uses to display its contents. The type of the ViewHolder must match the type declared in the Adapter class signature. Typically, it would set the view by inflating an XML layout file. Because the view holder is not yet assigned to any particular data, the method does not actually set the view’s contents.

Add a following onCreateViewHolder() and ViewHolder to your Adapter.

// Create UI View Holder from XML layout
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmployeesAdapter.ViewHolder {
  val layoutInflater = LayoutInflater.from(parent.context)
  val view = layoutInflater.inflate(R.layout.employee_item, parent, false)
  return ViewHolder(view)
}

// View Holder class to hold UI views
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
  val nameTextView: TextView = view.nameTextView
}

You will get error message from employee_item layout, because it has not been created yet.

The layout manager binds the view holder to its data. It does this by calling the adapter’s onBindViewHolder() method, and passing the view holder’s position in the RecyclerView. The onBindViewHolder() method needs to fetch the appropriate data, and use it to fill in the view holder’s layout.

Add a following onBindViewHolder() to your Adapter.

// Bind data to UI View Holder
override fun onBindViewHolder(
  holder: EmployeesAdapter.ViewHolder, 
  position: Int) 
{
  // employee to bind UI
  val employee: JSONObject = employees.getJSONObject(position)
  // employee lastname and firstname
  holder.nameTextView.text = 
     employee["lastName"].toString() 
     + " " 
     + employee["firstName"].toString()
}

Final method what is needed inside an Adapter is getItemCount(). Add a following method to your adapter.

// Return item count in employees
override fun getItemCount(): Int = employees.length()

Add a view holder layout

Create a new layout file for each of the employees. Name the layout file to employee_item.xml and drop one TextView inside it and give it name nameTextView. This layout will be used in above ViewHolder class.

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

  <TextView
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/nameTextView" 
    android:layout_marginTop="5dp" 
    android:layout_marginStart="5dp"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Run and test

Build and run your application and it should display the employee names in a RecyclerView.

Display more employees data in a RecyclerView cell

Modify employee’s item layout file, so it displays an employee name, title, email, phone, department and image. Remember try to use different layout managers.

More data to UI

Modify ViewHolder to bind a more data to UI views and use Glide to display employee’s image.

// View Holder class to hold UI views
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
  val nameTextView: TextView = view.nameTextView
  // add other Views here: title, email, ...
}

Use imageView to get it’s content: imageView.context with Glide.

// Bind data to UI View Holder
override fun onBindViewHolder(holder: EmployeesAdapter.ViewHolder, position: Int) {
  // employee to bind UI
  val employee: JSONObject = employees.getJSONObject(position)
  // employee lastname and firstname
  holder.nameTextView.text = employee["lastName"].toString() + " " + employee["firstName"].toString()
  // title, email, phone, department, image
  // to get context in Glide, you can use holder.imageView.context
}

Run and test

Build and run your application and it should display the employee’s data in a RecyclerView cell. Now images are rounded with Glide. Don’t worry about that, you can leave those as a rectangles. You can try to find a way to get rounded ones.

Multipage application

Enable list-item selection

The recyclerview-selection library enables users to select items from the RecyclerView list using touch or mouse input. You retain control over the visual presentation of a selected item. You can also retain control over policies controlling selection behavior, such as items that can be eligible for selection, and how many items can be selected.

Sometimes it is easier just a listen what happens in a ViewHolder class. You can add a setOnClickListener to it:

// add a item click listener
init {
  itemView.setOnClickListener {
    Toast.makeText(
      view.context,
      "Employee name is ${nameTextView.text}, adapter position = $adapterPosition",
      Toast.LENGTH_LONG).show()
  }
}

Now selection only Toast a message with selected employee name and it’s position in an Adapter. Remember remove unnecessary Toast messages, before you are publishing your Android application to Google Play.

New Employee activity and layout

You need to add a new Activity and it’s layout to show a selected Employee. Use your mouse right button and select your App folder from the project. Select New > Activity > Empty Activity. Give a name EmployeeActivity and generate layout files.

Start a new Activity

Use an explicit intent to start a new EmployeeActivity from the ViewHolder. Selected employee JSON data can be added to intent as an extras string.

// Add a item click listener
init {
  itemView.setOnClickListener {
    // create an explicit intent
    val intent = Intent(view.context, EmployeeActivity::class.java)
    // add selected employee JSON as a string data
    intent.putExtra("employee",employees[adapterPosition].toString())
    // start a new activity
    view.context.startActivity(intent)
  }
}

Get employee’s data in EmployeeActivity

You can get employee’s data from the intent in a EmployeeActivity‘s onCreate() method. In a below, Toast will be used as a test to show an employees name.

// EmployeeActivity's onCreate
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_employee)

  // get data from intent
  val bundle: Bundle? = intent.extras;
  if (bundle != null) {
    val employeeString = bundle!!.getString("employee")
    val employee = JSONObject(employeeString)
    val name = employee["firstName"]
    // modify here to display other employee's data too!
    Toast.makeText(this, "Name is $name",Toast.LENGTH_LONG).show()
  }
}

EmployeeActivity’s Layout

Modify EmployeeActivity‘s layout to display selected employees data. Be innovative!

Test

Run your application. Now it should load data and show it in the RecyclerView. Select one of the employee and a new activity should be launched and selected employee’s data are visible in the UI.

Add comment

Pasi Manninen

Pasi Manninen

Pasi is a mobile and web application developer. Currently working as a senior lecturer in JAMK University of Applied Sciences. Pasi has programming experience over many decades and has taught dozens of courses since the 90's.

Recent Posts

Follow Me