In the course of this tutorial, we will take a look into the new Swipe to refresh layout introduced in material design.

Android Lollipop is baked with some of the finests looking user interface widgets and UI design guidelines, and what they call it as Material Design. Some of the widgets are fine tuned while some new of them are added to the SDK.

The Swipe to refresh layout is used to indicate  user while the content of a screen is being updated. The Swipe to refresh layout was earlier introduced in Android 4.4 Kitkat, and was named as SwipeRefreshLayout. Visually it was represented just below ActionBar.

Since Android Lollipop, the visual representation of the swipe to refresh layout has been changed drastically. It appears as a circular refresh animation, horizontally centered and appears right below the Toolbar. Checkout official documentation for Swipe to refresh layout in android Lollipop.

Swipe to Refresh Layout Example

In this example, we will create the sample application that downloads the data from a server feed, and displays on a ListView. It also allow user the ability to swipe down and request for updated data from server.

Output of this example is as following video.


Now without wasting much of time, lets us move straight into its implementation. To implement Swipe to refresh layout, you will need the v4 support library. You can include the v4 support library to your project by adding below dependency in build.gradle file.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "com.android.support:appcompat-v7:21.0.+"
}

Secondly, let us define the swipe to refresh layout and list view to show the feed response. Create a new layout file inside res/layout folder, name it as activity_main.xml and paste the below code snippets.

activity_main.xml

<android.support.v4.widget.SwipeRefreshLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></ListView>
</android.support.v4.widget.SwipeRefreshLayout>

How it works

  • The ListView is placed as a child view to SwipeRefreshLayout.
  • This allows user the ability to show the loading spinner when user swipes the ListView edge. All the functionality of displaying loading bar is encapsulated inside SwipeRefreshLayout class.
  • When user swipes down, the OnRefreshListener events gets fired. You can handle this event to write the logic for downloading or refreshing data.
  • Note that, once data is downloaded, user has to manually call setRefreshing(false) to hide the refresh spinner.

Let us now initialize the SwipeRefreshLayout and ListView from activity and write the logic to download data from server.

In this example we are downloading data form server and parsing JSON response before we rendering it on the ListView. Please refer Android Networking Tutorial for understanding more on this code.

MainActivity.java

public class MainActivity extends ActionBarActivity {

    private ListView mListView = null;
    private ArrayAdapter mAdapter = null;
    private SwipeRefreshLayout mSwipeRefreshLayout = null;

    private String[] feedList = null;
    private String feedUrl = "http://stacktips.com/api/get_category_posts/?dev=1&slug=android";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mListView = (ListView) findViewById(R.id.listView);

        //Start Downloading data
        new DownloadFilesTask().execute(feedUrl);

        //Initialize swipe to refresh view
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                //Refreshing data on server
                new DownloadFilesTask().execute(feedUrl);
            }
        });
    }


    private void updateList() {
        ArrayAdapter mAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, feedList);
        mListView.setAdapter(mAdapter);

        if (mSwipeRefreshLayout.isRefreshing()) {
            mSwipeRefreshLayout.setRefreshing(false);
        }
    }


    private class DownloadFilesTask extends AsyncTask<String, Void, Void> {

        @Override
        protected void onProgressUpdate(Void... values) {
        }

        @Override
        protected void onPostExecute(Void result) {
            if (null != feedList) {
                updateList();
            }
        }

        @Override
        protected Void doInBackground(String... params) {
            // getting JSON string from URL
            JSONObject json = getJSONFromUrl(params[0]);

            //parsing json data
            parseJson(json);
            return null;
        }
    }

    public JSONObject getJSONFromUrl(String url) {
        InputStream is = null;
        JSONObject jObj = null;
        String json = null;

        try {
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost(url);

            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            is = httpEntity.getContent();

            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            json = sb.toString();

            jObj = new JSONObject(json);

        } catch (Exception e) {
            Log.e("Error", "Error parsing data " + e.toString());
        }
        return jObj;
    }


    public void parseJson(JSONObject json) {
        try {
            if (json.getString("status").equalsIgnoreCase("ok")) {
                JSONArray posts = json.getJSONArray("posts");

                feedList = new String[posts.length()];
                for (int i = 0; i < posts.length(); i++) {
                    JSONObject post = (JSONObject) posts.getJSONObject(i);
                    feedList[i] = post.getString("title");
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

Download

Nilanchala

A blogger, a bit of tech freak and a software developer. He is a thought leader in the fusion of design and mobile technologies. He is the author of Xamarin Mobile Application Development for Android Book (goo.gl/qUZ0XV3), DZone MVB and founder of stacktips.com.

Related Articles

Join The Discussion

Please note: We reserve the right to delete comments that contains snarky remarks, offensive or off-topic. To know more read our comments policy.
  • Susheel

    can you please check its not working sir error in doing in background method
    parseJsonFeed(json);

    package com.impresa.labs;

    import java.io.BufferedReader;

    import java.io.ByteArrayOutputStream;

    import java.io.File;

    import java.io.InputStream;

    import java.io.InputStreamReader;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.Locale;

    import android.app.Activity;

    import android.app.ProgressDialog;

    import android.content.Intent;

    import android.content.pm.PackageManager;

    import android.graphics.Bitmap;

    import android.graphics.BitmapFactory;

    import android.graphics.Color;

    import android.graphics.drawable.BitmapDrawable;

    import android.graphics.drawable.ColorDrawable;

    import android.net.Uri;

    import android.os.AsyncTask;

    import android.os.Bundle;

    import android.os.Environment;

    import android.provider.MediaStore;

    import android.util.Log;

    import android.view.View;

    import android.widget.AdapterView;

    import android.widget.ArrayAdapter;

    import android.widget.Button;

    import android.widget.TextView;

    import android.widget.Toast;

    import android.os.Bundle;

    import android.support.v4.app.Fragment;

    import android.support.v4.app.ListFragment;

    import android.support.v4.widget.SwipeRefreshLayout;

    import android.view.LayoutInflater;

    import android.view.MenuInflater;

    import android.view.MenuItem;

    import android.view.View;

    import android.view.ViewGroup;

    import info.androidhive.listviewfeed.adapter.FeedListAdapter;

    import info.androidhive.listviewfeed.app.AppController;

    import info.androidhive.listviewfeed.data.FeedItem;

    import java.io.UnsupportedEncodingException;

    import java.util.ArrayList;

    import java.util.List;

    import org.apache.http.HttpEntity;

    import org.apache.http.HttpResponse;

    import org.apache.http.client.methods.HttpPost;

    import org.apache.http.impl.client.DefaultHttpClient;

    import org.json.JSONArray;

    import org.json.JSONException;

    import org.json.JSONObject;

    import android.annotation.SuppressLint;

    import android.app.Activity;

    import android.content.Intent;

    import android.graphics.Color;

    import android.graphics.drawable.ColorDrawable;

    import android.os.Bundle;

    import android.view.Menu;

    import android.view.View.OnClickListener;

    import android.widget.Button;

    import android.widget.ListView;

    import info.androidhive.listviewfeed.adapter.FeedListAdapter;

    import com.android.volley.Cache;

    import com.android.volley.Cache.Entry;

    import com.android.volley.Request.Method;

    import com.android.volley.Response;

    import com.android.volley.VolleyError;

    import com.android.volley.VolleyLog;

    import com.android.volley.toolbox.JsonObjectRequest;

    import com.android.volley.toolbox.NetworkImageView;

    import com.impresa.labs.MainActivity;

    import com.impresa.labs.R;

    public class Stories extends Fragment {

    private static final String TAG = Stories.class.getSimpleName();

    private ProgressDialog pDialog;

    private ListView listView;

    private FeedListAdapter listAdapter;

    private List feedItems;

    private String URL_FEED = “http://jokesnstuffs.com/projectx/onlystory.php”;

    private static final String TAG_NAME = “name”;

    private static final String TAG_TIMESTAMP = “timestamp”;

    private static final String TAG_STATUS = “txtStatusMsg”;

    private Button update, feedback;

    private SwipeRefreshLayout mSwipeRefreshLayout = null;

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

    Bundle savedInstanceState) {

    setHasOptionsMenu(true);

    View rootView = inflater.inflate(R.layout.fragment_top_rated,

    container, false);

    listView = (ListView) rootView.findViewById(R.id.list);

    rootView.findViewById(R.id.allow);

    feedItems = new ArrayList();

    listAdapter = new FeedListAdapter(getActivity(), feedItems);

    listView.setOnItemClickListener(new Click2());

    listView.setAdapter(listAdapter);

    update = (Button) rootView.findViewById(R.id.deny3);

    new DownloadFilesTask().execute(URL_FEED);

    //Initialize swipe to refresh view

    mSwipeRefreshLayout = (SwipeRefreshLayout)rootView.findViewById(R.id.swipeRefreshLayout);

    mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {

    @Override

    public void onRefresh() {

    //Refreshing data on server

    new DownloadFilesTask().execute(URL_FEED);

    }

    });

    update.setOnClickListener(new OnClickListener() {

    @Override

    public void onClick(View v) {

    // TODO Auto-generated method stub

    Intent nxt = new Intent(getActivity(), Feedback.class);

    startActivity(nxt);

    }

    });

    feedback = (Button) rootView.findViewById(R.id.deny3);

    update.setOnClickListener(new OnClickListener() {

    @Override

    public void onClick(View v) {

    // TODO Auto-generated method stub

    Intent nxt = new Intent(getActivity(), Feedback.class);

    startActivity(nxt);

    }

    });

    Cache cache = AppController.getInstance().getRequestQueue().getCache();

    Entry entry = cache.get(URL_FEED);

    if (entry != null) {

    // fetch the data from cache

    try {

    String data = new String(entry.data, “UTF-8”);

    try {

    parseJsonFeed(new JSONObject(data));

    } catch (JSONException e) {

    e.printStackTrace();

    }

    } catch (UnsupportedEncodingException e) {

    e.printStackTrace();

    }

    } else {

    // making fresh volley request and getting json

    JsonObjectRequest jsonReq = new JsonObjectRequest(Method.GET,

    URL_FEED, null, new Response.Listener() {

    @Override

    public void onResponse(JSONObject response) {

    VolleyLog.d(TAG, “Response: ” + response.toString());

    if (response != null) {

    parseJsonFeed(response);

    }

    }

    }, new Response.ErrorListener() {

    @Override

    public void onErrorResponse(VolleyError error) {

    VolleyLog.d(TAG, “Error: ” + error.getMessage());

    }

    });

    // Adding request to volley request queue

    AppController.getInstance().addToRequestQueue(jsonReq);

    }

    return rootView;

    }

    private void updateList() {

    ArrayAdapter mAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, feedItems);

    listView.setAdapter(mAdapter);

    if (mSwipeRefreshLayout.isRefreshing()) {

    mSwipeRefreshLayout.setRefreshing(false);

    }

    }

    private class DownloadFilesTask extends AsyncTask {

    @Override

    protected void onProgressUpdate(Void… values) {

    }

    @Override

    protected void onPostExecute(Void result) {

    if (null != feedItems) {

    updateList();

    }

    }

    @Override

    protected Void doInBackground(String… params) {

    // getting JSON string from URL

    JSONObject json = getJSONFromUrl(params[0]);

    //parsing json data

    parseJsonFeed(json);

    return null;

    }

    }

    public JSONObject getJSONFromUrl(String url) {

    InputStream is = null;

    JSONObject jObj = null;

    String json = null;

    try {

    DefaultHttpClient httpClient = new DefaultHttpClient();

    HttpPost httpPost = new HttpPost(url);

    HttpResponse httpResponse = httpClient.execute(httpPost);

    HttpEntity httpEntity = httpResponse.getEntity();

    is = httpEntity.getContent();

    BufferedReader reader = new BufferedReader(new InputStreamReader(is, “iso-8859-1”), 8);

    StringBuilder sb = new StringBuilder();

    String line = null;

    while ((line = reader.readLine()) != null) {

    sb.append(line + “n”);

    }

    is.close();

    json = sb.toString();

    jObj = new JSONObject(json);

    } catch (Exception e) {

    Log.e(“Error”, “Error parsing data ” + e.toString());

    }

    return jObj;

    }

    private void parseJsonFeed(JSONObject response) {

    try {

    JSONArray feedArray = response.getJSONArray(“contacts”);

    for (int i = 0; i < feedArray.length(); i++) {

    JSONObject feedObj = (JSONObject) feedArray.get(i);

    FeedItem item = new FeedItem();

    item.setName(feedObj.getString("name"));

    item.setStatus(feedObj.getString("status"));

    item.setTimeStamp(feedObj.getString("timeStamp"));

    feedItems.add(item);

    }

    // notify data changes to list adapater

    listAdapter.notifyDataSetChanged();

    } catch (JSONException e) {

    e.printStackTrace();

    }

    }

    private class Click2 implements ListView.OnItemClickListener {

    @Override

    public void onItemClick(AdapterView parent, View view, int position,

    long id) {

    String name = ((TextView) view.findViewById(R.id.name)).getText()

    .toString();

    String status = ((TextView) view.findViewById(R.id.txtStatusMsg))

    .getText().toString();

    String timestamp = ((TextView) view.findViewById(R.id.timestamp))

    .getText().toString();

    // String bitmap =

    // ((Movie)feedItems.get(position)).getThumbnailUrl();

    Intent in = new Intent(getActivity(), SingleActivity2.class);

    in.putExtra(TAG_NAME, name);

    in.putExtra(TAG_TIMESTAMP, timestamp);

    in.putExtra(TAG_STATUS, status);

    // in.putExtra(“images”, bitmap);

    startActivity(in);

    }

    }

    @Override

    public void onDestroy() {

    super.onDestroy();

    hidePDialog();

    }

    private void hidePDialog() {

    if (pDialog != null) {

    pDialog.dismiss();

    pDialog = null;

    }

    }

    }

  • Susheel

    package com.impresa.labs;

    import java.io.BufferedReader;

    import java.io.ByteArrayOutputStream;

    import java.io.File;

    import java.io.InputStream;

    import java.io.InputStreamReader;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.Locale;

    import android.app.Activity;

    import android.app.ProgressDialog;

    import android.content.Intent;

    import android.content.pm.PackageManager;

    import android.graphics.Bitmap;

    import android.graphics.BitmapFactory;

    import android.graphics.Color;

    import android.graphics.drawable.BitmapDrawable;

    import android.graphics.drawable.ColorDrawable;

    import android.net.Uri;

    import android.os.AsyncTask;

    import android.os.Bundle;

    import android.os.Environment;

    import android.provider.MediaStore;

    import android.util.Log;

    import android.view.View;

    import android.widget.AdapterView;

    import android.widget.ArrayAdapter;

    import android.widget.Button;

    import android.widget.TextView;

    import android.widget.Toast;

    import android.os.Bundle;

    import android.support.v4.app.Fragment;

    import android.support.v4.app.ListFragment;

    import android.support.v4.widget.SwipeRefreshLayout;

    import android.view.LayoutInflater;

    import android.view.MenuInflater;

    import android.view.MenuItem;

    import android.view.View;

    import android.view.ViewGroup;

    import info.androidhive.listviewfeed.adapter.FeedListAdapter;

    import info.androidhive.listviewfeed.app.AppController;

    import info.androidhive.listviewfeed.data.FeedItem;

    import java.io.UnsupportedEncodingException;

    import java.util.ArrayList;

    import java.util.List;

    import org.apache.http.HttpEntity;

    import org.apache.http.HttpResponse;

    import org.apache.http.client.methods.HttpPost;

    import org.apache.http.impl.client.DefaultHttpClient;

    import org.json.JSONArray;

    import org.json.JSONException;

    import org.json.JSONObject;

    import android.annotation.SuppressLint;

    import android.app.Activity;

    import android.content.Intent;

    import android.graphics.Color;

    import android.graphics.drawable.ColorDrawable;

    import android.os.Bundle;

    import android.view.Menu;

    import android.view.View.OnClickListener;

    import android.widget.Button;

    import android.widget.ListView;

    import info.androidhive.listviewfeed.adapter.FeedListAdapter;

    import com.android.volley.Cache;

    import com.android.volley.Cache.Entry;

    import com.android.volley.Request.Method;

    import com.android.volley.Response;

    import com.android.volley.VolleyError;

    import com.android.volley.VolleyLog;

    import com.android.volley.toolbox.JsonObjectRequest;

    import com.android.volley.toolbox.NetworkImageView;

    import com.impresa.labs.MainActivity;

    import com.impresa.labs.R;

    public class Stories extends Fragment {

    private static final String TAG = Stories.class.getSimpleName();

    private ProgressDialog pDialog;

    private ListView listView;

    private FeedListAdapter listAdapter;

    private List feedItems;

    private String URL_FEED = “http://jokesnstuffs.com/projectx/onlystory.php”;

    private static final String TAG_NAME = “name”;

    private static final String TAG_TIMESTAMP = “timestamp”;

    private static final String TAG_STATUS = “txtStatusMsg”;

    private Button update, feedback;

    private SwipeRefreshLayout mSwipeRefreshLayout = null;

    @Override

    public View onCreateView(LayoutInflater inflater, ViewGroup container,

    Bundle savedInstanceState) {

    setHasOptionsMenu(true);

    View rootView = inflater.inflate(R.layout.fragment_top_rated,

    container, false);

    listView = (ListView) rootView.findViewById(R.id.list);

    rootView.findViewById(R.id.allow);

    feedItems = new ArrayList();

    listAdapter = new FeedListAdapter(getActivity(), feedItems);

    listView.setOnItemClickListener(new Click2());

    listView.setAdapter(listAdapter);

    update = (Button) rootView.findViewById(R.id.deny3);

    new DownloadFilesTask().execute(URL_FEED);

    //Initialize swipe to refresh view

    mSwipeRefreshLayout = (SwipeRefreshLayout)rootView.findViewById(R.id.swipeRefreshLayout);

    mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {

    @Override

    public void onRefresh() {

    //Refreshing data on server

    new DownloadFilesTask().execute(URL_FEED);

    }

    });

    update.setOnClickListener(new OnClickListener() {

    @Override

    public void onClick(View v) {

    // TODO Auto-generated method stub

    Intent nxt = new Intent(getActivity(), Feedback.class);

    startActivity(nxt);

    }

    });

    feedback = (Button) rootView.findViewById(R.id.deny3);

    update.setOnClickListener(new OnClickListener() {

    @Override

    public void onClick(View v) {

    // TODO Auto-generated method stub

    Intent nxt = new Intent(getActivity(), Feedback.class);

    startActivity(nxt);

    }

    });

    Cache cache = AppController.getInstance().getRequestQueue().getCache();

    Entry entry = cache.get(URL_FEED);

    if (entry != null) {

    // fetch the data from cache

    try {

    String data = new String(entry.data, “UTF-8”);

    try {

    parseJsonFeed(new JSONObject(data));

    } catch (JSONException e) {

    e.printStackTrace();

    }

    } catch (UnsupportedEncodingException e) {

    e.printStackTrace();

    }

    } else {

    // making fresh volley request and getting json

    JsonObjectRequest jsonReq = new JsonObjectRequest(Method.GET,

    URL_FEED, null, new Response.Listener() {

    @Override

    public void onResponse(JSONObject response) {

    VolleyLog.d(TAG, “Response: ” + response.toString());

    if (response != null) {

    parseJsonFeed(response);

    }

    }

    }, new Response.ErrorListener() {

    @Override

    public void onErrorResponse(VolleyError error) {

    VolleyLog.d(TAG, “Error: ” + error.getMessage());

    }

    });

    // Adding request to volley request queue

    AppController.getInstance().addToRequestQueue(jsonReq);

    }

    return rootView;

    }

    private void updateList() {

    ArrayAdapter mAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, feedItems);

    listView.setAdapter(mAdapter);

    if (mSwipeRefreshLayout.isRefreshing()) {

    mSwipeRefreshLayout.setRefreshing(false);

    }

    }

    private class DownloadFilesTask extends AsyncTask {

    @Override

    protected void onProgressUpdate(Void… values) {

    }

    @Override

    protected void onPostExecute(Void result) {

    if (null != feedItems) {

    updateList();

    }

    }

    @Override

    protected Void doInBackground(String… params) {

    // getting JSON string from URL

    JSONObject json = getJSONFromUrl(params[0]);

    //parsing json data

    parseJsonFeed(json);

    return null;

    }

    }

    public JSONObject getJSONFromUrl(String url) {

    InputStream is = null;

    JSONObject jObj = null;

    String json = null;

    try {

    DefaultHttpClient httpClient = new DefaultHttpClient();

    HttpPost httpPost = new HttpPost(url);

    HttpResponse httpResponse = httpClient.execute(httpPost);

    HttpEntity httpEntity = httpResponse.getEntity();

    is = httpEntity.getContent();

    BufferedReader reader = new BufferedReader(new InputStreamReader(is, “iso-8859-1”), 8);

    StringBuilder sb = new StringBuilder();

    String line = null;

    while ((line = reader.readLine()) != null) {

    sb.append(line + “n”);

    }

    is.close();

    json = sb.toString();

    jObj = new JSONObject(json);

    } catch (Exception e) {

    Log.e(“Error”, “Error parsing data ” + e.toString());

    }

    return jObj;

    }

    private void parseJsonFeed(JSONObject response) {

    try {

    JSONArray feedArray = response.getJSONArray(“contacts”);

    for (int i = 0; i < feedArray.length(); i++) {

    JSONObject feedObj = (JSONObject) feedArray.get(i);

    FeedItem item = new FeedItem();

    item.setName(feedObj.getString("name"));

    item.setStatus(feedObj.getString("status"));

    item.setTimeStamp(feedObj.getString("timeStamp"));

    feedItems.add(item);

    }

    // notify data changes to list adapater

    listAdapter.notifyDataSetChanged();

    } catch (JSONException e) {

    e.printStackTrace();

    }

    }

    private class Click2 implements ListView.OnItemClickListener {

    @Override

    public void onItemClick(AdapterView parent, View view, int position,

    long id) {

    String name = ((TextView) view.findViewById(R.id.name)).getText()

    .toString();

    String status = ((TextView) view.findViewById(R.id.txtStatusMsg))

    .getText().toString();

    String timestamp = ((TextView) view.findViewById(R.id.timestamp))

    .getText().toString();

    // String bitmap =

    // ((Movie)feedItems.get(position)).getThumbnailUrl();

    Intent in = new Intent(getActivity(), SingleActivity2.class);

    in.putExtra(TAG_NAME, name);

    in.putExtra(TAG_TIMESTAMP, timestamp);

    in.putExtra(TAG_STATUS, status);

    // in.putExtra(“images”, bitmap);

    startActivity(in);

    }

    }

    @Override

    public void onDestroy() {

    super.onDestroy();

    hidePDialog();

    }

    private void hidePDialog() {

    if (pDialog != null) {

    pDialog.dismiss();

    pDialog = null;

    }

    }

    }

  • zicaros

    thx u sir

  • Eric

    Works except for the fact that when I refresh, it duplicates the already existing list items

    • You have to careful check while making the request for same page. Placing a database logic is preferable.

  • Eric

    Works fine except for the fact that when I refresh, it duplicates the already existing list items

  • You must retain the scroll position of the list. And use listView.scrollToPosition() method to scroll to the position where user left previously.