Pull to Refresh with RecyclerView in Android with Example
The SwipeRefreshLayout widget is used for implementing a swipe-to-refresh user interface design pattern. Where the user uses the vertical swipe gesture to refresh the content of the views. The vertical swipe is detected by the SwipeRefreshLayout widget and it displays a distinct progress bar and triggers the callback methods in the app. In order to use this behaviour, we need to use the SwipeRefreshLayout widget as the parent of a ListView or GridView. These Material Design UI Patterns are seen in applications like Gmail, Youtube, Facebook, Instagram, etc. It allows the user to refresh the application manually. SwipeRefreshLayout class contains a listener called OnRefreshListener. The classes which want to use this listener should implement SwipeRefreshLayout.OnRefreshListener interface. On vertical swipe-down gesture, this listener is triggered and onRefresh() method is called and can be overridden according to the needs.
Example
In this example, we would store data into the ArrayList which is used for populating the RecyclerView. Whenever onRefresh() method is called the ArrayList data gets rearranged. A sample GIF is given below to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Java language.
Let us check a example implementing the concept.
Step-by-Step Implementation
Step 1: Create a New Project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio.
Note that select Java/Kotlin as the programming language.
Directory Structure:
Note: There are some extra elements in drawable which are used in recycler view.
Step 2: Adding dependencies
We are going to use RecyclerView and SwipeRefreshLayout. So, we need to add dependencies for them. For adding these dependencies Go to Gradle Scripts > build.gradle(Module: app) and add the following dependencies. After adding these dependencies you need to click on Sync Now.
dependencies {
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
}
Before moving further let’s add some color attributes in order to enhance the app bar. Go to app > res > values > colors.xml and add the following color attributes.
colors.xml:
<resources>
<color name="colorPrimary">#0F9D58</color>
<color name="colorPrimaryDark">#16E37F</color>
<color name="colorAccent">#03DAC5</color>
</resources>
Step 3: Working with the activity_main.xml file
In this step, we will create SwipeRefreshLayout and Add RecyclerView to it. Go to app > res > layout > activity_main.xml and add the following code snippet.
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/swipeRefreshLayout"
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" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Layout:
Step 4: Create a new layout file list_item.xml for the list items of RecyclerView.
Go to the app > res > layout > right-click > New > Layout Resource File and name it as list_item. list_item.xml layout file contains an ImageView and a TextView which is used for populating the rows of RecyclerView.
list_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="horizontal"
android:padding="10dp">
<!--For image src we have used ic_launcher
and for text "GeeksForGeeks they are used only for
reference how it will looks"-->
<ImageView
android:id="@+id/imageView"
android:layout_width="120dp"
android:layout_height="120dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="10dp"
android:text="GeeksForGeeks" />
</LinearLayout>
Layout:
Step 5: Creating Adapter class for RecyclerView
Now, we will create an Adapter.java class that will extend the RecyclerView.Adapter with ViewHolder. Go to the app > java > package > right-click and create a new java class and name it as Adapter. In Adapter class we will override the onCreateViewHolder() method which will inflate the list_item.xml layout and pass it to View Holder. Then onBindViewHolder() method where we set data to the Views with the help of View Holder. Below is the code snippet for Adapter.java class.
Adapter File:
package com.gfg.recyclerview_pull;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
// Extends the Adapter class to RecyclerView.Adapter
// and implement the unimplemented methods
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
ArrayList images, text;
Context context;
// Constructor for initialization
public Adapter(Context context, ArrayList images, ArrayList text) {
this.context = context;
this.images = images;
this.text = text;
}
@NonNull
@Override
public Adapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// Inflating the Layout(Instantiates list_item.xml layout file into View object)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
// Passing view to ViewHolder
Adapter.ViewHolder viewHolder = new Adapter.ViewHolder(view);
return viewHolder;
}
// Binding data to the into specified position
@Override
public void onBindViewHolder(@NonNull Adapter.ViewHolder holder, int position) {
// TypeCast Object to int type
int res = (int) images.get(position);
holder.images.setImageResource(res);
holder.text.setText((CharSequence) text.get(position));
}
@Override
public int getItemCount() {
// Returns number of items currently available in Adapter
return text.size();
}
// Initializing the Views
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView images;
TextView text;
public ViewHolder(View view) {
super(view);
images = (ImageView) view.findViewById(R.id.imageView);
text = (TextView) view.findViewById(R.id.textView);
}
}
}
package com.gfg.recyclerview_pull
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
// Extends the Adapter class to RecyclerView.Adapter
// and implement the unimplemented methods
class Adapter // Constructor for initialization
(var context: Context, var images: ArrayList<*>, var text: ArrayList<*>) :
RecyclerView.Adapter<Adapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// Inflating the Layout(Instantiates list_item.xml layout file into View object)
val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
// Passing view to ViewHolder
val viewHolder: ViewHolder = ViewHolder(view)
return viewHolder
}
// Binding data to the into specified position
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// TypeCast Object to int type
val res = images[position] as Int
holder.images.setImageResource(res)
holder.text.text = text[position] as CharSequence
}
override fun getItemCount(): Int {
// Returns number of items currently available in Adapter
return text.size
}
// Initializing the Views
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
var images: ImageView = view.findViewById<View>(R.id.imageView) as ImageView
var text: TextView = view.findViewById<View>(R.id.textView) as TextView
}
}
Step 6: Working with MainActivity.java file
In MainActivity.java class we create two ArrayList for storing images and text. These images are placed in the drawable folder(app > res > drawable). You can use any images in place of this. And then we get the reference of SwipeRefreshLayout and RecyclerView and set the LayoutManager and Adapter to show items in RecyclerView and implement onRefreshListener. Below is the code for the MainActivity.java file.
MainActivity File:
package com.gfg.recyclerview_pull;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
SwipeRefreshLayout swipeRefreshLayout;
RecyclerView recyclerView;
// Using ArrayList to store images and text data
ArrayList images = new ArrayList<>(Arrays.asList(R.drawable.battery, R.drawable.bluetooth_disabled,
R.drawable.nfc, R.drawable.security_update_warning,
R.drawable.signal_cellular_1_bar, R.drawable.signal_cellular_2_bar
, R.drawable.wifi_off));
ArrayList text = new ArrayList<>(Arrays.asList("Battery Stats", "Bluetooth", "NFC", "Security Update", "Sim 1", "Sim 2", "Wifi"));
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Getting reference of swipeRefreshLayout and recyclerView
swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
// Setting the layout as Linear for vertical orientation to have swipe behavior
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(linearLayoutManager);
// Sending reference and data to Adapter
Adapter adapter = new Adapter(MainActivity.this, images, text);
// Setting Adapter to RecyclerView
recyclerView.setAdapter(adapter);
// SetOnRefreshListener on SwipeRefreshLayout
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(false);
RearrangeItems();
}
});
}
public void RearrangeItems() {
// Shuffling the data of ArrayList using system time
Collections.shuffle(images, new Random(System.currentTimeMillis()));
Collections.shuffle(text, new Random(System.currentTimeMillis()));
Adapter adapter = new Adapter(MainActivity.this, images, text);
recyclerView.setAdapter(adapter);
}
}
package com.gfg.recyclerview_pull
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import java.util.Arrays
import java.util.Collections
import java.util.Random
class MainActivity : AppCompatActivity() {
var swipeRefreshLayout: SwipeRefreshLayout? = null
var recyclerView: RecyclerView? = null
// Using ArrayList to store images and text data
var images: ArrayList<*> = ArrayList(
Arrays.asList<Any>(
R.drawable.battery,
R.drawable.bluetooth_disabled,
R.drawable.nfc,
R.drawable.security_update_warning,
R.drawable.signal_cellular_1_bar,
R.drawable.signal_cellular_2_bar,
R.drawable.wifi_off
)
)
var text: ArrayList<*> = ArrayList(
mutableListOf(
"Battery Stats",
"Bluetooth",
"NFC",
"Security Update",
"Sim 1",
"Sim 2",
"Wifi"
)
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Getting reference of swipeRefreshLayout and recyclerView
swipeRefreshLayout = findViewById<View>(R.id.swipeRefreshLayout) as SwipeRefreshLayout
recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
// Setting the layout as Linear for vertical orientation to have swipe behavior
val linearLayoutManager = LinearLayoutManager(applicationContext)
recyclerView!!.layoutManager = linearLayoutManager
// Sending reference and data to Adapter
val adapter = Adapter(this@MainActivity, images, text)
// Setting Adapter to RecyclerView
recyclerView!!.adapter = adapter
// SetOnRefreshListener on SwipeRefreshLayout
swipeRefreshLayout!!.setOnRefreshListener {
swipeRefreshLayout!!.isRefreshing = false
RearrangeItems()
}
}
fun RearrangeItems() {
// Shuffling the data of ArrayList using system time
Collections.shuffle(images, Random(System.currentTimeMillis()))
Collections.shuffle(text, Random(System.currentTimeMillis()))
val adapter = Adapter(this@MainActivity, images, text)
recyclerView!!.adapter = adapter
}
}