SwipeRefreshLayout - Android

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 http://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="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://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="http://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();

}