In my previous article I gave a brief overview of Volley, including why Volley created, it’s features, Android Networking problems before Volley etc. The length of the tutorial was getting really long so it was not possible to cover all the topics in that article. In this article I will finish what was left and give you a useful working example of Volley.
In this tutorial I will load JSON from network using Volley and populate that data in RecyclerView.
What should you already know?
- RecyclerView or ListView – Custom RecyclerView to populate data
- Basics of Volley – How to setup Volley as Android Module project & Volley Basics
I’m going to parse this JSON for this project, it looks like,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[{ "title": "RecyclerView", "image": "http://www.androidnovice.com/wp-content/uploads/2016/06/recycle-1.png", "ratebar": 89, "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book." }, .. .. .. .. .. .. { "title": "Custom GridView", "image": "http://www.androidnovice.com/wp-content/uploads/2015/10/CustomGridView.png", "ratebar": 100, "content": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book." }] |
Now let’s start our project,
First Create a new project from File -> New -> New Project, Name it VolleyDemo & Select Empty Activity (We will build everything from scratch).
1> In your build.gradle file add this dependencies,
1 2 3 4 |
compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:recyclerview-v7:23.1.1' compile 'com.android.support:cardview-v7:23.1.1' compile project(':volley') |
2> Create a new Java Class file NetworkController.java
This file will be a Singleton Class of Volley Request Queue. The benefit of making it Singleton is that the Object will last until the end of our application life cycle and every new request will be handle by only one object.
Here is the code, I have commented wherever it’s necessary,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
package com.androidnovice.volleydemo; import android.content.Context; import android.graphics.Bitmap; import android.support.v4.util.LruCache; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.Volley; /** * Created by AndroidNovice on 6/2/2016. */ public class NetworkController { private RequestQueue mRequestQueue; private ImageLoader mImageLoader; private static Context mCtx; private static NetworkController mInstance; private NetworkController(Context context) { mCtx = context; mRequestQueue = getRequestQueue(); // This will Load Images from Network in Separate Thread mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() { //Create ImageCache of max size 10MB private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(10); @Override public Bitmap getBitmap(String url) { return cache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { cache.put(url, bitmap); } }); } public static synchronized NetworkController getInstance(Context context) { if (mInstance == null) { mInstance = new NetworkController(context); } return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { // getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in. mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req) { getRequestQueue().add(req); } public ImageLoader getImageLoader() { return mImageLoader; } } |
As you can see Inside the private constructor I have created LRU Cache, LRU stands for Least Recently Used, It is in Memory Cache means that the cache will be stored inside the Memory, It has a size limit of 10MB, as soon as the Cache Size will grow more than 10MB, the LRUCache algorithm will remove the least used item and cache the new item. ImageLoader will automatically check for the Image in cache if not available than it will Load Image from URL.
3> In your activity_main.xml paste below code,
1 2 3 4 5 6 7 8 9 10 11 12 |
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.androidnovice.volleydemo.MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> |
4> Create a new Layout file as singleitem_recyclerview.xml and paste below code,
This is the layout file for our Single List Item.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.CardView android:id="@+id/card_view" android:layout_width="match_parent" android:layout_height="wrap_content" card_view:cardCornerRadius="2dp" card_view:cardElevation="3dp" card_view:cardUseCompatPadding="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <com.android.volley.toolbox.NetworkImageView android:id="@+id/thumbnail" android:layout_width="match_parent" android:layout_height="200dp" android:layout_alignParentLeft="true" android:layout_marginBottom="10dp" /> <TextView android:id="@+id/title_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="7dp" android:text="this is title" android:textColor="@color/primaryText" android:textSize="20sp" android:textStyle="bold" /> <ProgressBar android:id="@+id/ratingbar_view" style="?android:attr/progressBarStyleHorizontal" android:layout_width="match_parent" android:layout_height="10dp" android:layout_margin="7dp" android:max="100" /> <TextView android:id="@+id/content_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="7dp" android:layout_marginLeft="7dp" android:layout_marginRight="7dp" android:text="this is lorem ipsum content of universe" android:textColor="@color/secondaryText" android:textSize="17sp" /> </LinearLayout> </android.support.v7.widget.CardView> </LinearLayout> |
5>Open colors.xml and paste,
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#9C27B0</color> <color name="colorPrimaryDark">#7B1FA2</color> <color name="colorAccent">#FF5722</color> <color name="primaryText">#212121</color> <color name="secondaryText">#727272</color> </resources> |
6>Create a new file NewsFeeds.java,
This file is Simple POJO which will hold values of our JSON,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
package com.androidnovice.volleydemo; /** * Created by AndroidNovice on 6/5/2016. */ //Simple POJO to hold values of our JSON public class NewsFeeds { private String imgURL, feedName, content; private int rating; public NewsFeeds(String name, String content, String imgurl, int rating) { this.feedName = name; this.content = content; this.imgURL = imgurl; this.rating = rating; } public String getContent() { return content; } public String getImgURL() { return imgURL; } public String getFeedName() { return feedName; } public int getRating() { return rating; } } |
7> Create a New file MyRecyclerAdapter.java and write down below code,
This is a Custom Adapter for our RecyclerView which implements ViewHolder pattern, If you are not familier with recyclerview I will suggest to first follow this tutorial.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
package com.androidnovice.volleydemo; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.android.volley.toolbox.NetworkImageView; import java.util.List; /** * Created by AndroidNovice on 6/5/2016. */ public class MyRecyclerAdapter extends RecyclerView.Adapter<MyRecyclerAdapter.MyViewHolder> { private List<NewsFeeds> feedsList; private Context context; private LayoutInflater inflater; public MyRecyclerAdapter(Context context, List<NewsFeeds> feedsList) { this.context = context; this.feedsList = feedsList; inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View rootView = inflater.inflate(R.layout.singleitem_recyclerview, parent, false); return new MyViewHolder(rootView); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { NewsFeeds feeds = feedsList.get(position); //Pass the values of feeds object to Views holder.title.setText(feeds.getFeedName()); holder.content.setText(feeds.getContent()); holder.imageview.setImageUrl(feeds.getImgURL(), NetworkController.getInstance(context).getImageLoader()); holder.ratingbar.setProgress(feeds.getRating()); } @Override public int getItemCount() { return feedsList.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { private TextView content, title; private NetworkImageView imageview; private ProgressBar ratingbar; public MyViewHolder(View itemView) { super(itemView); title = (TextView) itemView.findViewById(R.id.title_view); content = (TextView) itemView.findViewById(R.id.content_view); // Volley's NetworkImageView which will load Image from URL imageview = (NetworkImageView) itemView.findViewById(R.id.thumbnail); ratingbar = (ProgressBar) itemView.findViewById(R.id.ratingbar_view); ratingbar.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Toast.makeText(context, "Rated By User : " + feedsList.get(getAdapterPosition()).getRating(), Toast.LENGTH_SHORT).show(); } }); } } } |
8> Finally, in your MainActivity.java write down this,
All code is self explanatory, Follow this tutorial if you don’t know how to make JSON Request using Volley.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
package com.androidnovice.volleydemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonArrayRequest; import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { RequestQueue queue; String url = "https://api.myjson.com/bins/w86a"; RecyclerView recyclerView; List<NewsFeeds> feedsList = new ArrayList<NewsFeeds>(); MyRecyclerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Initialize RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview); adapter = new MyRecyclerAdapter(this, feedsList); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(adapter); //Getting Instance of Volley Request Queue queue = NetworkController.getInstance(this).getRequestQueue(); //Volley's inbuilt class to make Json array request JsonArrayRequest newsReq = new JsonArrayRequest(url, new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray response) { for (int i = 0; i < response.length(); i++) { try { JSONObject obj = response.getJSONObject(i); NewsFeeds feeds = new NewsFeeds(obj.getString("title"), obj.getString("content"), obj.getString("image"), obj.getInt("ratebar")); // adding movie to movies array feedsList.add(feeds); } catch (Exception e) { System.out.println(e.getMessage()); } finally { //Notify adapter about data changes adapter.notifyItemChanged(i); } } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { System.out.println(error.getMessage()); } }); //Adding JsonArrayRequest to Request Queue queue.add(newsReq); } } |
9> Add Internet permission to AndroidManifest.xml,
1 |
<uses-permission android:name="android.permission.INTERNET"></uses-permission> |
If you have done everything mentioned above the project should work fine. You can experiment using your JSON try to change Cache value, make a simple String request, just get used to it so it will be really easier for you to create something on your own.
If you are having any error or need source code mention below in the comments.
Hi androidnovice
nice explanation ,helped me lot in understanding volley library example with recycler view
but from single item recycler view.xml; u remove the root linear layout as it is unnecessary ,because its increaing the gap between cardview on scrolling when we have diffrent size images
please i need the source code with json text file
Can I get the source code of the proyect?
Is it published in Github.com?
Thanks
Hi Bro,
Excellent tutorial and well explained.
Thanks..
in my case when i adding volly dependencies it showing me error could not find volly…
this code works perfectly, but there are little bugs.
1. there are large spaces between each cardviews in the recycler view, so set the linearlayout
when you scroll to the end aand you start scrolling back, the last cardview items repeats itself several times, to fix it,your linearlayout which is the parent of the cardview, set the layout_width to “wrap content”
2. when you scroll to the end of the recyclerview and you start scrolling back up, the last cardview would repeat itself several times before scrolling up. to fix this, you need to edit your adapter codes, let it look like this.
package com.motivational.videos.sposh;
/**
* Created by user on 11/1/2017.
*/
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.volley.toolbox.NetworkImageView;
import java.util.List;
/**
* Created by AndroidNovice on 6/5/2016.
*/
public class MyRecyclerAdapter_featured extends RecyclerView.Adapter {
private List feedsList;
private Context context;
private LayoutInflater inflater;
public MyRecyclerAdapter_featured(Context context, List feedsList) {
this.context = context;
this.feedsList = feedsList;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View rootView = inflater.inflate(R.layout.singleitem_recyclerview_featured, parent, false);
return new MyViewHolder(rootView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
NewsFeeds_featured feeds = feedsList.get(position);
//Pass the values of feeds object to Views
holder.setTitle(feeds.getFeedName());
holder.setContent(feeds.getContent());
// holder.setImage(feeds.getImgURL(), NetworkController_featured.getInstance(context).getImageLoader());
holder.setRating(String.valueOf(feeds.getRating()));
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemViewType(int position) {
return position;
}
@Override
public int getItemCount() {
return feedsList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private TextView content, title, ratingbar;
private NetworkImageView imageview;
public MyViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title_view_featured);
content = (TextView) itemView.findViewById(R.id.content_view_featured);
// Volley’s NetworkImageView which will load Image from URL
imageview = (NetworkImageView) itemView.findViewById(R.id.thumbnail_featured);
ratingbar = (TextView) itemView.findViewById(R.id.ratingbar_view_featured);
ratingbar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// Toast.makeText(context, “Rated By User : ” + feedsList.get(getAdapterPosition()).getRating(), Toast.LENGTH_SHORT).show();
}
});
}
public void setTitle(String s) {
title.setText(s);
}
public void setContent(String s) {
content.setText(s);
}
public void setRating(String s) {
ratingbar.setText(s);
}
}
}
1. correction. your linearlayout which is the parent of the cardview, set the layout_height to “wrap content