SwipeRefreshLayout - Android
Last updated Dec 06, 2019 Now a days pull-down refresh and pull-up loading functions are mandatory for the applications.
For this android provides SwipeRefreshLayout to implement these functions.
In this post we are going to learn how to use SwipeRefreshLayout with Androidx libraries.
What is SwipeRefreshLayout?
Android SwipeRefreshLayout is a ViewGroup that can hold only one scrollable child. It can be either a ScrollView, ListView or RecyclerView.
This SwipeRefreshLayout consists a listener OnRefreshListener which contains override method is OnRefresh()
This method will called upon swipe down the layout.
Some other properties are
setRefreshing(boolean): enables or disables progress visibility.
isRefreshing(): checks whether the view is refreshing.
setColorScheme(): it receive four different colors that will be used to colorize the animation.
setDistanceToTriggerSync (int) – Used to set the distance to trigger a sync

Let's create an android App in Android studio, while creating project
enable androidx support
In this post i am going to fetch data from api using Retrofit Network library.
Lets add necesary dependencies to app level gradle file
//Androidx Material
implementation 'com.google.android.material:material:1.0.0'
//Retrofit
//Retrofit & GSON & RxJava
implementation "io.reactivex.rxjava2:rxjava:$RxJava"
implementation "io.reactivex.rxjava2:rxandroid:$RxAndroid"
implementation "com.squareup.retrofit2:retrofit:$Retrofit"
implementation "com.squareup.retrofit2:converter-gson:$Retrofit"
implementation "com.squareup.retrofit2:adapter-rxjava:$Retrofit"
implementation "com.google.code.gson:gson:$Gson"
update these with latest versions
RxJava = '2.2.0'
RxAndroid = '2.1.1'
Retrofit = '2.6.1'
Gson = '2.8.5'
|
I am going to use News API (https://newsapi.org/),
Generate POJO classes from JSON String by https://www.jsonschema2pojo.org/
Pojo classes will be like below
NewsResult.java
package com.rrtutors.swiperefreshlayout.apis;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class NewsResult {
@SerializedName("status")
@Expose
private String status;
@SerializedName("sources")
@Expose
private List sources = null;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List getSources() {
return sources;
}
public void setSources(List sources) {
this.sources = sources;
}
}
|
News.java
package com.rrtutors.swiperefreshlayout.apis;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class News {
@SerializedName("id")
@Expose
private String id;
@SerializedName("name")
@Expose
private String name;
@SerializedName("description")
@Expose
private String description;
@SerializedName("url")
@Expose
private String url;
@SerializedName("category")
@Expose
private String category;
@SerializedName("language")
@Expose
private String language;
@SerializedName("country")
@Expose
private String country;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
|
Now lets create Repository class to hanlde the Retrofit Instance
package com.rrtutors.swiperefreshlayout.apis;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class Repository {
static Retrofit instance;
public static Retrofit getRetrofit()
{
if(instance!=null)
return instance;
instance=new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl("https://dev.tutorialspoint.com/")
.client(new OkHttpClient.Builder().build())
.build();
return instance;
}
}
|
Now we are going add handle swiperefreshlayout events.
Initialize swiferefreshlayout and recyclerview and adapter in activity class
swiperefresh=findViewById(R.id.swiperefresh);
recyclerview=findViewById(R.id.recyclerview);
recyclerview.setLayoutManager(new LinearLayoutManager(this,RecyclerView.VERTICAL,false));
newsItemAdapter=new NewsItemAdapter();
recyclerview.setAdapter(newsItemAdapter);
|
call api by
private void callRequest()
{
new Handler().post(new Runnable() {
@Override
public void run() {
ApiCall call= Repository.getRetrofit().create(ApiCall.class);
Call result= call.fetchNews();
result.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
swiperefresh.setRefreshing(false);
Log.v("Response","Response "+response);
if(response.isSuccessful())
{
if(response.body().getStatus().equals("ok"))
{
newsItemAdapter.addNews(response.body().getSources());
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
swiperefresh.setRefreshing(false);
Log.v("Response","Response Error "+t.getMessage());
}
});
}
});
}
Hanld Refresh events
swiperefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
swiperefresh.setRefreshing(true);
callRequest();
}
});
on Swipe the layout down this will execute and fetch the data from API and update on list.
|
Complete code
package com.rrtutors.swiperefreshlayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import com.rrtutors.swiperefreshlayout.apis.ApiCall;
import com.rrtutors.swiperefreshlayout.apis.NewsResult;
import com.rrtutors.swiperefreshlayout.apis.Repository;
public class RecyclerActivity extends AppCompatActivity {
SwipeRefreshLayout swiperefresh;
RecyclerView recyclerview;
NewsItemAdapter newsItemAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
swiperefresh=findViewById(R.id.swiperefresh);
recyclerview=findViewById(R.id.recyclerview);
recyclerview.setLayoutManager(new LinearLayoutManager(this,RecyclerView.VERTICAL,false));
newsItemAdapter=new NewsItemAdapter();
recyclerview.setAdapter(newsItemAdapter);
swiperefresh.setColorSchemeColors(new int[]{R.color.green,R.color.purple});
swiperefresh.setDistanceToTriggerSync(50);
swiperefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
swiperefresh.setRefreshing(true);
callRequest();
}
});
callRequest();
}
private void callRequest()
{
new Handler().post(new Runnable() {
@Override
public void run() {
ApiCall call= Repository.getRetrofit().create(ApiCall.class);
Call result= call.fetchNews();
result.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
swiperefresh.setRefreshing(false);
Log.v("Response","Response "+response);
if(response.isSuccessful())
{
if(response.body().getStatus().equals("ok"))
{
newsItemAdapter.addNews(response.body().getSources());
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
swiperefresh.setRefreshing(false);
Log.v("Response","Response Error "+t.getMessage());
}
});
}
});
}
}
|
activity_recycler.xml
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="center"
android:orientation="vertical">
android:id="@+id/btn_recylerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="#fff"
android:onClick="recyclerview"
android:textColor="#673AB7"
android:textAllCaps="false"
android:textStyle="bold"
android:text="Recyclerview"
/>
android:id="@+id/btn_recylerview_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Grid Layout"
android:textAllCaps="false"
android:onClick="gridlayout"
android:background="#fff"
android:textColor="#673AB7"
android:textStyle="bold"
/>
|
NewsAdapter.java
package com.rrtutors.swiperefreshlayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.rrtutors.swiperefreshlayout.apis.News;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class NewsItemAdapter extends RecyclerView.Adapter {
ListlistNews;
NewsItemAdapter()
{
listNews=new ArrayList<>();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_list_item,parent,false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.txt_title.setText(listNews.get(position).getName());
holder.txt_desc.setText(listNews.get(position).getDescription());
holder.txt_country.setText(listNews.get(position).getCountry().toUpperCase());
}
@Override
public int getItemCount() {
return listNews.size();
}
public void addNews(ListlistNew)
{
listNews.clear();
listNews.addAll(listNew);
notifyDataSetChanged();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView txt_title;
TextView txt_desc;
TextView txt_country;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txt_title=itemView.findViewById(R.id.txt_title);
txt_desc=itemView.findViewById(R.id.txt_desc);
txt_country=itemView.findViewById(R.id.txt_country);
}
}
}
|
layout_list_item.xml
xmlns:app="https://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_margin="5dp"
app:cardElevation="5dp"
app:cardCornerRadius="4dp"
app:contentPadding="5dp"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
android:id="@+id/txt_title"
android:layout_width="wrap_content"
android:textSize="18sp"
android:layout_margin="3dp"
android:textColor="#9C27B0"
android:layout_height="wrap_content" />
android:id="@+id/txt_desc"
android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_margin="3dp"
android:textColor="#8B888B"
android:layout_height="wrap_content" />
android:id="@+id/txt_country"
android:layout_width="wrap_content"
android:textSize="18sp"
android:layout_gravity="right"
android:textColor="#009688"
android:layout_margin="3dp"
android:layout_height="wrap_content" />
|
Api.class
package com.rrtutors.swiperefreshlayout.apis;
import com.google.gson.JsonElement;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
public interface ApiCall {
public static final String BASE_IRL="https://newsapi.org/";
public static final String SUB_IRL="v2/sources?apiKey=PUT_HERE_NEWS_API_KEY";
@GET(SUB_IRL)
public CallfetchNews();
}
|
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".MainActivity">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_gravity="center"
android:orientation="vertical">
android:id="@+id/btn_recylerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="#fff"
android:onClick="recyclerview"
android:textColor="#673AB7"
android:textAllCaps="false"
android:textStyle="bold"
android:text="Recyclerview"
/>
android:id="@+id/btn_recylerview_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Grid Layout"
android:textAllCaps="false"
android:onClick="gridlayout"
android:background="#fff"
android:textColor="#673AB7"
android:textStyle="bold"
/>
NewsAdapter.java
package com.rrtutors.swiperefreshlayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.rrtutors.swiperefreshlayout.apis.News;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class NewsItemAdapter extends RecyclerView.Adapter {
ListlistNews;
NewsItemAdapter()
{
listNews=new ArrayList<>();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_list_item,parent,false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.txt_title.setText(listNews.get(position).getName());
holder.txt_desc.setText(listNews.get(position).getDescription());
holder.txt_country.setText(listNews.get(position).getCountry().toUpperCase());
}
@Override
public int getItemCount() {
return listNews.size();
}
public void addNews(ListlistNew)
{
listNews.clear();
listNews.addAll(listNew);
notifyDataSetChanged();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView txt_title;
TextView txt_desc;
TextView txt_country;
public ViewHolder(@NonNull View itemView) {
super(itemView);
txt_title=itemView.findViewById(R.id.txt_title);
txt_desc=itemView.findViewById(R.id.txt_desc);
txt_country=itemView.findViewById(R.id.txt_country);
}
}
}
|
layout_list_item.xml
xmlns:app="https://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_margin="5dp"
app:cardElevation="5dp"
app:cardCornerRadius="4dp"
app:contentPadding="5dp"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
android:id="@+id/txt_title"
android:layout_width="wrap_content"
android:textSize="18sp"
android:layout_margin="3dp"
android:textColor="#9C27B0"
android:layout_height="wrap_content" />
android:id="@+id/txt_desc"
android:layout_width="wrap_content"
android:textSize="14sp"
android:layout_margin="3dp"
android:textColor="#8B888B"
android:layout_height="wrap_content" />
android:id="@+id/txt_country"
android:layout_width="wrap_content"
android:textSize="18sp"
android:layout_gravity="right"
android:textColor="#009688"
android:layout_margin="3dp"
android:layout_height="wrap_content" />
|
Api.class
package com.rrtutors.swiperefreshlayout.apis;
import com.google.gson.JsonElement;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
public interface ApiCall {
public static final String BASE_IRL="https://newsapi.org/";
public static final String SUB_IRL="v2/sources?apiKey=PUT_HERE_NEWS_API_KEY";
@GET(SUB_IRL)
public CallfetchNews();
}
|
-->