Home Android ListView : Swipe To Refresh – Simulate Updates With Handlers

Android ListView : Swipe To Refresh – Simulate Updates With Handlers

Android ListView : 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 ListView 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 listview.

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 ListView'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.swiperefreshlistviewexample"
        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.swiperefreshlistviewexample;

/**
 * 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 : Adapter class

ItemClickListener inetrface

Main Responsibility : DEFINES ITEMCLICK EVENT HANDER SIGNATURE

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

 

package com.tutorials.hp.swiperefreshlistviewexample;

/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public interface ItemClickListener {

    void onItemClick();

}

 

 

 

View Holder class

Main Responsibility : HOLD VIEWS FOR RECYCLING.

  • In this case textviews and imageviews.

 

package com.tutorials.hp.swiperefreshlistviewexample;

import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public class MyViewHolder implements View.OnClickListener {

    ImageView img;
    TextView nameTxt;
    ItemClickListener itemClickListener;

    public MyViewHolder(View v) {
        img= (ImageView) v.findViewById(R.id.movieImage);
        nameTxt= (TextView) v.findViewById(R.id.nameTxt);

        v.setOnClickListener(this);

    }

    public  void setItemClickListener(ItemClickListener ic)
    {
        this.itemClickListener=ic;
    }

    @Override
    public void onClick(View v) {
        this.itemClickListener.onItemClick();
    }
}

 

 

 

Custom Adapter class

Main Responsibility : HELPS US BIND CUSTOM DATA TO LISTVIEW.

  • You can use one line of code to bind simple data to listview.
  • But for custom data like ours,we need an adapter to adapt it.
  • We shall use BaseAdapter as our Base class.
  • Our BaseAdapter subclass shall receive an arraylist and a context.
  • We shall simulate fetching updates.
  • We do this in background thread using Handlers.
  • Meanwhile we show a progress circle.

 

package com.tutorials.hp.swiperefreshlistviewexample;

import android.content.Context;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Random;

/**
 * Created by Oclemmy on 3/30/2016 for ProgrammingWizards Channel.
 */
public class CustomAdapter extends BaseAdapter {

    Context c;
    ArrayList<Movie> movies;
    SwipeRefreshLayout swipe;

    LayoutInflater inflater;

    public CustomAdapter(Context c, ArrayList<Movie> movies,SwipeRefreshLayout swipe) {
        this.c = c;
        this.movies = movies;
        this.swipe=swipe;
    }

    @Override
    public int getCount() {
        return movies.size();
    }

    @Override
    public Object getItem(int position) {
        return movies.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        if(inflater==null)
        {
            inflater= (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        if(convertView==null)
        {
            convertView=inflater.inflate(R.layout.model,parent,false);
        }

        MyViewHolder holder=new MyViewHolder(convertView);
        holder.nameTxt.setText(movies.get(position).getName());
        holder.img.setImageResource(movies.get(position).getImage());

        holder.setItemClickListener(new ItemClickListener() {
            @Override
            public void onItemClick() {
                Toast.makeText(c, movies.get(position).getName(), Toast.LENGTH_SHORT).show();
            }
        });

        swipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                refresh();
            }
        });

        return convertView;
    }

    private void refresh()
    {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                movies.add(0,movies.get(new Random().nextInt(movies.size())));

                CustomAdapter.this.notifyDataSetChanged();

                swipe.setRefreshing(false);

            }
        },3000);
    }


}











 

 

 

SECTION 4 : Our Activity

MainActivity class.

Main Responsibility : LAUNCH OUR APP.

  • We shall reference the views like ListView 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 ListView.

 

package com.tutorials.hp.swiperefreshlistviewexample;

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.Toolbar;
import android.view.View;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ListView lv;
    CustomAdapter adapter;
    SwipeRefreshLayout swipe;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

        lv= (ListView) findViewById(R.id.lv);
        swipe= (SwipeRefreshLayout) findViewById(R.id.swiper);
        final ArrayList<Movie> movies=getMovies();
        adapter=new CustomAdapter(this,movies,swipe);

        lv.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.swiperefreshlistviewexample.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.swiperefreshlistviewexample.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">

        <ListView
            android:id="@+id/lv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            >
        </ListView>

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

11 − five =

2 comments

joshua February 27, 2017 at 11:29 am

hello sir i was asking what modifications will i have to make in case i was using volley to get json data into a listview

Reply
Oclemy February 27, 2017 at 2:32 pm

Hello I would recommend you use a different http api than volley as its no longer maintained.

Reply

Leave a Comment

eighteen − 4 =