Skip to content

Exercise 07 - Show employees in a RecyclerView

Project name : E07 Employees app

Introduction

This exercise teaches how to load JSON data from the web and show loaded data in a RecyclerView. Application will show all employees in a list and detailed information in different activity.

 

Employees 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. If you don’t have any server or you have some problems to generate JSON data, you can use my sample data.

Tip

You should try to create your own file and save it to your own server.

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:

1
https://randomuser.me/api/portraits/(wo)?{0,1}men/\d{1,2}.jpg

Use same Field Names what are visible at the below picture, when you generate your own JSON structure.

!Image 02

Click image to see it bigger.

It will generate a following JSON structure:

!Image 01

Note

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

Check that your JSON file is valid. You can use JSON Formatter & Validator.

Create a new project

  • Create a new project and name it to E07 Employees app, include Kotlin support
  • Remember save your project in your android-exercises folder
  • Set Phone and Tablet target and select newest API
  • Use Empty Activity template
  • Configure Activity as default settings

Use Volley to load JSON data

Open 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.

Click to see a solution - first try to code it by yourself
1
2
3
4
dependencies {
  ...
  implementation 'com.android.volley:volley:1.2.1'
}

Add RecyclerView to your main layout

Remove TexView element from your main layout and 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.

!Image 03

Click image to see it bigger!

Allow Internet permission

Now you are loading JSON from the web, so you need to add internet permission to your application manifest file. You can also use/add android:usesCleartextTraffic="true" attribute to application element in manifest to allow data loading from HTTP, if you aren't using HTTPS.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.employeesapp">

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

  <application
    ...
  </application>
</manifest>

Start loading JSON data

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.

Learn how to load JSON with Volley: Make a standard request and load employees data in onCreate function.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.example.employeesapp

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.android.volley.Request
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley

class MainActivity : AppCompatActivity() {

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

    // start loading JSON data
    loadJSON()
  }

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

Build and test

Run your application and you should see Log-message in your LogCat window in Android Studio. So, array of employees data is loaded correctly.

1
2
3
4
5
6
2021-03-16 10:32:42.015 7679-7679/com.example.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"},
 ...

Note

If you don't find your loaded data from the LogCat window, then try to figure out what is wrong - read all the 'red' error messages in LogCat window.

Connect loaded 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.

Read more:

Define recyclerView variable and use LinearLayoutManager with your RecyclerView.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class MainActivity : AppCompatActivity() {
  // Define recyclerView
  private lateinit var recyclerView:RecyclerView

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

    // Find recyclerView from the layout
    recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
    // Use LinearManager as a layout manager for recyclerView
    recyclerView.layoutManager = LinearLayoutManager(this)

    // start loading JSON data
    loadJSON()
  }

  // ...
}

Add EmployeesAdapter to your recyclerView's adapter after data is loaded in your loadJSON function. EmployeesAdapter will be created later in this exercise. You will need to pass employees data into adapter with a parameters.

Click to see a solution - first try to code it by yourself
1
2
3
4
5
6
7
8
9
//...
val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
{ response ->
  // Get employees from JSON
  val employees = response.getJSONArray("employees")
  // Create Employees Adapter with employees data
  recyclerView.adapter = EmployeesAdapter(employees)
},
//...

Add an Employees 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. Remember send your highscore array here as a parameter.

Click to see a solution - first try to code it by yourself
1
2
3
4
// Employees Adapter, used in RecyclerView in MainActivity
class EmployeesAdapter(private val employees: JSONArray) 
  : RecyclerView.Adapter<EmployeesAdapter.ViewHolder>() {
}

Note

You will get error with ViewHolder. You will create it later in this exercise.

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.

Create a onCreateViewHolder() and ViewHolder to your Adapter. Now onCreateViewHolder should load employee_item layout from the resources. And later when a recyclerView need display a new employee, it will automatically call ViewHolder to return layouts nameTextView TextView object.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 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.findViewById(R.id.nameTextView)
}

Note

You will get a few errors with missing layout variables. You will create a layout files later in this exercise.

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.

Create a needed onBindViewHolder() function to your Adapter.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 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
  // TASK: you can modify this to use formatting strings with placeholders
  holder.nameTextView.text = 
    employee["lastName"].toString()+" "+ employee["firstName"].toString()
}

Final method what is needed inside an Adapter is getItemCount(). Creat it to your adapter. Remember use employees length here.

Click to see a solution - first try to code it by yourself
1
2
// Return item count in employees
override fun getItemCount(): Int = employees.length()

Create a ViewHolder 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.

Remember use wrap_content attribute in layout_height, then employee text is only using height space as much as it needs. If you use match_parent in it, it will use the whole UI space and you will see only one employee name in the UI.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?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.

!Image 04

Display more employees data in a RecyclerView

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.

!Image 05

Show more data with ViewHolder

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

1
2
3
4
5
// View Holder class to hold UI views
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
  val nameTextView: TextView = view.findViewById(R.id.nameTextView)
  // Add other Views in here: title, email, ...
}

Modify onBindViewHolder to display other data in the layout

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 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
  // TASK: you can modify this to use formatting strings with placeholders
  holder.nameTextView.text = 
    employee["lastName"].toString()+" "+ employee["firstName"].toString()
  // Add title, email, phone, department, image
  // to get image 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.

!Image 06

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// View Holder class to hold UI views
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
  //...

  // 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.

 

Add a 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.

!Image 09

Note

Check your Android Manifest file and note that a new activity element is added in your application. It will use EmployeeActivity Kotlin class.

Start a new activity

Use an explicit intent to start a new EmployeeActivity from the ViewHolder. Add selected employee JSON data to Intent as a string extras.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Add a item click listener
init {
  itemView.setOnClickListener {
    // remove or comment earlier Toast-message

    // 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)
  }
}

You can test your application now. Click one of the employees and your application moves a new activity, which is empty by default.

Get and show selected employee's data

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.

Click to see a solution - first try to code it by yourself
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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")
    if (employeeString != null) {
      val employee = JSONObject(employeeString)
      val name = employee["firstName"]
      Toast.makeText(this, "Name is $name",Toast.LENGTH_LONG).show()
    }
  }
}

You can test your application now. Click one of the employees and your application moves a new activity and a Toast message is shown.

Modify Employees Activity layout

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

 

Click to see more help - first try to code it by yourself
1
2
3
4
5
6
// Toast.makeText(this, "Name is $name",Toast.LENGTH_LONG).show()
// find employees title element from layout
val titleTextView: TextView = findViewById(R.id.titleTextView)
// show employees title
titleTextView.text = employee["title"].toString()
//...

Test and push

Test your application in emulator, take screenshots and commit/push your project and screenshots back to JAMKIT/GitLab. Remember move your exercise/issue ticket from Doing to In Review in Issues Board and write your learning comments to issue comments.