Android RecyclerView : Swipe To Refresh – Simulate Updates With Handlers

Android RecyclerView : Swipe To Refresh – Simulate Updates With Handlers







Introduction

SwipeRefreshLayout exists as a support library and enables implement the now popular Swipe to Refresh.Some call it Pull To Refresh,some drag to refresh but the concept is simple,pull or swipe down on your layout and this causes display of a small progress circle.We can then of course capitalize on that and refresh our dataset.

What we do :

  • Custom RecyclerView with cardviews with images and text.
  • Our data source is a simple arraylist.
  • Use SwipeRefreshlayout.
  • When user swipes down,we simulate downloading of fresh copies of data.
  • We do this in background thread using handlers.
  • Rebind the data to our recyclerview.

SECTION 1 : Our Dependencies

Build.Gradle

  • Android Studio has added for us dependencies for AppCompat and Design support libraries.
  • Note we are using AppCompatActivity.
  • Design support libraries are for cordinatorlayout,appbar layout,toolbar and floating action button.All contained in our ActivityMain.xml layout specification.Also swiperefreshlayout.
  • Our RecyclerView's ViewItems shall be cardviews.So add CardView also.

 

apply plugin: 'com.android.application'
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
    defaultConfig {
        applicationId "com.tutorials.hp.swiperefreshrecyclerview"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
    compile 'com.android.support:cardview-v7:23.2.1'
}

 

 

SECTION 2 : Our Data Object

Spacecraft.java

Main Responsibility : IS A SINGLE DATA OBJECT

  • Represents a single object.Here I'll use Movie.
  • The object shall have various properties like name,image etc.
  • Each object shall occupy a specific viewitem, here cardview.

 

package com.tutorials.hp.swiperefreshrecyclerview;
/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public class Movie {
    private String name;
    private int image;
    public Movie(String name, int image) {
        this.name = name;
        this.image = image;
    }
    public String getName() {
        return name;
    }
    public int getImage() {
        return image;
    }
}

 

 

 

SECTION 3 : ReyclerView classes

ItemClickListener inetrface

Main Responsibility : DEFINES ITEMCLICK EVENT HANDER SIGNATURE

  • Define our RecyclerView ViewItem's signature for our OnItemClick methods.

 

package com.tutorials.hp.swiperefreshrecyclerview;
/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public interface ItemClickListener {
    void onItemClick(int pos);
}

 

 

View Holder class

Main Responsibility : HOLD VIEWS FOR RECYCLING.

  • In this case textviews and imageviews.
  • Subclasses RecyclerView.ViewHolder.

 

package com.tutorials.hp.swiperefreshrecyclerview;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public class MyHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    ImageView img;
    TextView nameTxt;
    ItemClickListener itemClickListener;
    public MyHolder(View itemView) {
        super(itemView);
        img= (ImageView) itemView.findViewById(R.id.movieImage);
        nameTxt= (TextView) itemView.findViewById(R.id.nameTxt);
        itemView.setOnClickListener(this);
    }
    public void setItemClickListener(ItemClickListener ic)
    {
        this.itemClickListener=ic;
    }
    @Override
    public void onClick(View v) {
        this.itemClickListener.onItemClick(getLayoutPosition());
    }
}

 

 

Adapter class

Main Responsibility : HELPS US BIND CUSTOM DATA TO RECYCLERVIEW.

  • Subclasses RecyclerView.Adapter<ViewHolder>
  • Binds our dataset to our views.
  • Shall receive an arraylist and a context.
  • We shall simulate fetching updates.
  • We do this in background thread using Handlers.
  • Manwhile we show a progress circle.

 

package com.tutorials.hp.swiperefreshrecyclerview;
import android.content.Context;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Random;
/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public class MyAdapter extends RecyclerView.Adapter<MyHolder> {
    Context c;
    ArrayList<Movie> movies;
    SwipeRefreshLayout swiper;
    public MyAdapter(Context c, ArrayList<Movie> movies, SwipeRefreshLayout swiper) {
        this.c = c;
        this.movies = movies;
        this.swiper = swiper;
    }
    @Override
    public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v= LayoutInflater.from(parent.getContext()).inflate(R.layout.model,parent,false);
        MyHolder holder=new MyHolder(v);
        return holder;
    }
    @Override
    public void onBindViewHolder(MyHolder holder, int position) {
         holder.nameTxt.setText(movies.get(position).getName());
        holder.img.setImageResource(movies.get(position).getImage());
        holder.setItemClickListener(new ItemClickListener() {
            @Override
            public void onItemClick(int pos) {
                Toast.makeText(c, movies.get(pos).getName(), Toast.LENGTH_SHORT).show();
            }
        });
        swiper.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refresh();
            }
        });
    }
    @Override
    public int getItemCount() {
        return movies.size();
    }
    private void refresh()
    {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                movies.add(0,movies.get(new Random().nextInt(movies.size())));
                MyAdapter.this.notifyDataSetChanged();
                swiper.setRefreshing(false);
            }
        },3000);
    }
}

 

 

SECTION 4 : Our Activity

MainActivity class.

Main Responsibility : LAUNCH OUR APP.

  • We shall reference the views like RecyclerView and Floating action button here,from our XML Layouts.Also SwipeRefreshLayout.
  • We then generate our dataset and pass it to an instance of our adapter.
  • We set the adapter to our RecyclerView.

 

package com.tutorials.hp.swiperefreshrecyclerview;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
    RecyclerView rv;
    SwipeRefreshLayout swiper;
    MyAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        rv= (RecyclerView) findViewById(R.id.mRecycler);
        swiper= (SwipeRefreshLayout) findViewById(R.id.swiper);
        rv.setLayoutManager(new LinearLayoutManager(this));
        rv.setItemAnimator(new DefaultItemAnimator());
        final ArrayList<Movie> movies;
        movies=getMovies();
        adapter=new MyAdapter(this,movies,swiper);
        rv.setAdapter(adapter);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, String.valueOf(movies.size()), Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }
    private ArrayList<Movie> getMovies()
    {
        //COLECTION OF  MOVIES
        ArrayList<Movie> movies=new ArrayList<>();
        Movie movie=new Movie("Game Of Thrones",R.drawable.thrones);
        movies.add(movie);
        movie=new Movie("BlackList",R.drawable.red);
        movies.add(movie);
        movie=new Movie("Breaking Bad",R.drawable.breaking);
        movies.add(movie);
        movie=new Movie("Shuttle Carrier",R.drawable.shuttlecarrier);
        movies.add(movie);
        movie=new Movie("Fruits",R.drawable.fruits);
        movies.add(movie);
        movie=new Movie("Crisis",R.drawable.crisis);
        movies.add(movie);
        movie=new Movie("Ghost Rider",R.drawable.rider);
        movies.add(movie);
        movie=new Movie("Star Wars",R.drawable.starwars);
        movies.add(movie);
        movie=new Movie("Men In Black",R.drawable.meninblack);
        movies.add(movie);
        return movies;
    }
}

 

 

SECTION 5 : Our Layouts

ActivityMain.xml Layout.

  • Inflated as our activity's view.
  • Contains xml specifications for Cordinator Layout,appbar layout,toolbar as well as floating action button.All these are contained in Design Support library.
  • Includes content main where we define our view hierarchy.

 

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
    android:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.swiperefreshrecyclerview.MainActivity">
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />
    </android.support.design.widget.AppBarLayout>
    <include layout="@layout/content_main" />
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>

 

 

ContentMain.xml Layout.

  • Defines our view hierarchy.
  • Wraps our AdapterView with SwipeRefreshLayout.

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.swiperefreshrecyclerview.MainActivity"
    tools:showIn="@layout/activity_main">
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swiper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <android.support.v7.widget.RecyclerView
            android:id="@+id/mRecycler"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >
        </android.support.v7.widget.RecyclerView>
    </android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>

 

 

Model.xml Layout.

  • Inflated as our AdapterView's viewitems.
  • How our CardViews shall look.

 

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_margin="10dp"
    card_view:cardCornerRadius="10dp"
    card_view:cardElevation="10dp"
    android:layout_height="wrap_content">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/movieImage"
            android:padding="10dp"
            android:src="@drawable/ghost" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Name"
            android:id="@+id/nameTxt"
            android:padding="10dp"
            android:textColor="@color/colorAccent"
            android:layout_below="@+id/movieImage"
            android:layout_alignParentLeft="true"
             />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text=" John Doe a former FBI Agent and now Physics teacher .is wrongly accussed of murdering an innocent child.He makes it his business to find the bad guys who did taht.He convinces hacker Aram to join him.....
            "
            android:id="@+id/descTxt"
            android:padding="10dp"
            android:layout_below="@+id/nameTxt"
            android:layout_alignParentLeft="true"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="TV Show"
            android:id="@+id/posTxt"
            android:padding="10dp"
            android:layout_below="@+id/movieImage"
            android:layout_alignParentRight="true" />
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/chk"
            android:layout_alignParentRight="true"
            />
    </RelativeLayout>
</android.support.v7.widget.CardView>

 

 

 

SECTION 6 : Downloadable Source Reference

To be uploaded soon.

SECTION 7 : Our Result

LAST SECTION

Lets share more tips in OUR FB PAGE.

Cheers.



    Leave a Reply

    Your email address will not be published. Required fields are marked *

    two × 4 =

    COMMENTS