My previous tutorial Android Custom ListView covers customizing android list view with image and text. In this tutorial I am going to explain even more customized list view like Facebook, Google+ news feed where it contains multiple images and texts.

I used android volley network library to make http calls and download the images. As volley comes with powerful image caching mechanism, we don’t have to much worry about caching the requests and images.

android facebook like custom news feed view

Final Output

Following is the screenshot of final output of this tutorial.

android facebook like feed view

Example feed Json

To demonstrate this tutorial I created an example json feed which contains an array of json feed object. Each object defines single feed row where it contains information like feed id, profile pic, profile name, timestamp, status message and feed image.

You can access the json from here.

{
    "feed": [
        {
            "id": 1,
            "name": "National Geographic Channel",
            "image": "https://api.androidhive.info/feed/img/cosmos.jpg",
            "status": "\"Science is a beautiful and emotional human endeavor,\" says Brannon Braga, executive producer and director. \"And Cosmos is all about making science an experience.\"",
            "profilePic": "https://api.androidhive.info/feed/img/nat.jpg",
            "timeStamp": "1403375851930",
            "url": null
        },
        {
            "id": 2,
            "name": "TIME",
            "image": "https://api.androidhive.info/feed/img/time_best.jpg",
            "status": "30 years of Cirque du Soleil's best photos",
            "profilePic": "https://api.androidhive.info/feed/img/time.png",
            "timeStamp": "1403375851930",
            "url": "http://ti.me/1qW8MLB"
        }
    ]
}

In real world scenario, this feed json should be generated dynamically by reading a database.

1. Planning the Layout

Before start writing the code, I would like to plan the layout first. If you observe the feed view, it has information like name,timestamp, profile pic, feed image and url. For this we need TextView, ImageView and a listview to display the feed. Using the LinearLayout’s orientation property I have alligned the elements vertically and horizontally.

android facebook like list view layout

2. Downloading Volley.jar

If you are new to android volley library, I suggest you go through my previous article Android Volley Tutorial to understand what volley library is actually for. (In simple words volley is a networking library used to make HTTP calls)

Download the volley.jar and keep it aside.

Now let’s start by creating a new project.

3. Creating new project

1. Create a new project in Eclipse from File ⇒ New ⇒ Android Application Project and fill all the required information.

2. Open res ⇒ values ⇒ dimens.xml and add following dimensions. If you don’t have dimens.xml, create a new file and add these values.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    
    
    <dimen name="feed_item_margin">10dp</dimen>
    <dimen name="feed_item_padding_top_bottom">20dp</dimen>
    <dimen name="feed_item_padding_left_right">15dp</dimen>
    <dimen name="feed_item_profile_pic">50dp</dimen>
    <dimen name="feed_item_profile_info_padd">10dp</dimen>
    <dimen name="feed_item_profile_name">15dp</dimen>
    <dimen name="feed_item_timestamp">13dp</dimen>
    <dimen name="feed_item_status_pad_left_right">15dp</dimen>
    <dimen name="feed_item_status_pad_top">13dp</dimen>
    <dimen name="feed_item_corner_radius">3dp</dimen>
    <dimen name="feed_item_border_width">1dp</dimen>

</resources>

3. Also create another xml file named colors.xml under res ⇒ values and add following colors.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="white">#ffffff</color>
    <color name="feed_bg">#d3d6db</color>
    <color name="feed_item_bg">#ffffff</color>
    <color name="feed_item_border">#c2c3c8</color>
    <color name="link">#0a80d1</color>
    <color name="timestamp">#a0a3a7</color>    
</resources>

4. Under res ⇒ drawable, create a new file called bg_parent_rounded_corner.xml and paste the below code. This xml will give a rounded corner background to feed item.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <!-- view background color -->
    <solid android:color="@color/feed_item_bg" >
    </solid>

    <!-- view border color and width -->
    <stroke
        android:width="@dimen/feed_item_border_width"
        android:color="@color/feed_item_border" >
    </stroke>

    <!-- Here is the corner radius -->
    <corners android:radius="@dimen/feed_item_corner_radius" >
    </corners>

</shape>

5. To keep the project well organized, I am creating required packages first. Create 4 packages named app, adapter, data and volley. To create new package, right click on src ⇒ New ⇒ Package and give package name. Example: info.androidhive.listview.app.

Following is the project structure I am trying to achieve.

facebook_feed_eclipse_project

6. Now paste the volley.jar in project libs folder.

7. Create a class named LruBitmapCache.java under volley package and add the following code. This class takes care of caching network images on disk.

package info.androidhive.listviewfeed.volley;

import com.android.volley.toolbox.ImageLoader.ImageCache;

import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class LruBitmapCache extends LruCache<String, Bitmap> implements
		ImageCache {
	public static int getDefaultLruCacheSize() {
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
		final int cacheSize = maxMemory / 8;

		return cacheSize;
	}

	public LruBitmapCache() {
		this(getDefaultLruCacheSize());
	}

	public LruBitmapCache(int sizeInKiloBytes) {
		super(sizeInKiloBytes);
	}

	@Override
	protected int sizeOf(String key, Bitmap value) {
		return value.getRowBytes() * value.getHeight() / 1024;
	}

	@Override
	public Bitmap getBitmap(String url) {
		return get(url);
	}

	@Override
	public void putBitmap(String url, Bitmap bitmap) {
		put(url, bitmap);
	}
}

8. Under app package create class named AppController.java and paste the following content. This is a singleton class which initializes global instances of required classes. All the objects related to volley are initialized here.

package info.androidhive.listviewfeed.app;

import info.androidhive.listviewfeed.volley.LruBitmapCache;
import android.app.Application;
import android.text.TextUtils;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class AppController extends Application {

	public static final String TAG = AppController.class.getSimpleName();

	private RequestQueue mRequestQueue;
	private ImageLoader mImageLoader;
	LruBitmapCache mLruBitmapCache;

	private static AppController mInstance;

	@Override
	public void onCreate() {
		super.onCreate();
		mInstance = this;
	}

	public static synchronized AppController getInstance() {
		return mInstance;
	}

	public RequestQueue getRequestQueue() {
		if (mRequestQueue == null) {
			mRequestQueue = Volley.newRequestQueue(getApplicationContext());
		}

		return mRequestQueue;
	}

	public ImageLoader getImageLoader() {
		getRequestQueue();
		if (mImageLoader == null) {
			getLruBitmapCache();
			mImageLoader = new ImageLoader(this.mRequestQueue, mLruBitmapCache);
		}

		return this.mImageLoader;
	}

	public LruBitmapCache getLruBitmapCache() {
		if (mLruBitmapCache == null)
			mLruBitmapCache = new LruBitmapCache();
		return this.mLruBitmapCache;
	}

	public <T> void addToRequestQueue(Request<T> req, String tag) {
		req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
		getRequestQueue().add(req);
	}

	public <T> void addToRequestQueue(Request<T> req) {
		req.setTag(TAG);
		getRequestQueue().add(req);
	}

	public void cancelPendingRequests(Object tag) {
		if (mRequestQueue != null) {
			mRequestQueue.cancelAll(tag);
		}
	}
}

9. Now open your AndroidManifest.xml file and add Application.java class in <application> tag. Also we need to add INTERNET permission as this app makes network calls.

    <application
        android:name="info.androidhive.listviewfeed.app.AppController"> ....</application>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.listviewfeed"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:name="info.androidhive.listviewfeed.app.AppController"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="info.androidhive.listviewfeed.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

10. The main challenge in this project is adjusting the aspect ratio of feed image once it is downloaded. Unfortunately volley doesn’t provide any callback method once the NetworkImageView is loaded. So I created a custom ImageView class with callback methods. This class automatically adjusts the image height to prevent image aspect ratio distortion.

Under your project main package create a class named FeedImageView.java and paste the below code. I took the code from this stackoverflow answer and made few tweaks.

You can use this FeedImageView in your xml layout like this

<info.androidhive.listviewfeed.FeedImageView
            android:id="@+id/feedImage1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
package info.androidhive.listviewfeed;

import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;

import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.ImageLoader.ImageContainer;
import com.android.volley.toolbox.ImageLoader.ImageListener;

public class FeedImageView extends ImageView {

	public interface ResponseObserver {
		public void onError();

		public void onSuccess();
	}

	private ResponseObserver mObserver;

	public void setResponseObserver(ResponseObserver observer) {
		mObserver = observer;
	}

	/**
	 * The URL of the network image to load
	 */
	private String mUrl;

	/**
	 * Resource ID of the image to be used as a placeholder until the network
	 * image is loaded.
	 */
	private int mDefaultImageId;

	/**
	 * Resource ID of the image to be used if the network response fails.
	 */
	private int mErrorImageId;

	/**
	 * Local copy of the ImageLoader.
	 */
	private ImageLoader mImageLoader;

	/**
	 * Current ImageContainer. (either in-flight or finished)
	 */
	private ImageContainer mImageContainer;

	public FeedImageView(Context context) {
		this(context, null);
	}

	public FeedImageView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public FeedImageView(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);
	}

	/**
	 * Sets URL of the image that should be loaded into this view. Note that
	 * calling this will immediately either set the cached image (if available)
	 * or the default image specified by
	 * {@link VolleyImageView#setDefaultImageResId(int)} on the view.
	 * 
	 * NOTE: If applicable, {@link VolleyImageView#setDefaultImageResId(int)}
	 * and {@link VolleyImageView#setErrorImageResId(int)} should be called
	 * prior to calling this function.
	 * 
	 * @param url
	 *            The URL that should be loaded into this ImageView.
	 * @param imageLoader
	 *            ImageLoader that will be used to make the request.
	 */
	public void setImageUrl(String url, ImageLoader imageLoader) {
		mUrl = url;
		mImageLoader = imageLoader;
		// The URL has potentially changed. See if we need to load it.
		loadImageIfNecessary(false);
	}

	/**
	 * Sets the default image resource ID to be used for this view until the
	 * attempt to load it completes.
	 */
	public void setDefaultImageResId(int defaultImage) {
		mDefaultImageId = defaultImage;
	}

	/**
	 * Sets the error image resource ID to be used for this view in the event
	 * that the image requested fails to load.
	 */
	public void setErrorImageResId(int errorImage) {
		mErrorImageId = errorImage;
	}

	/**
	 * Loads the image for the view if it isn't already loaded.
	 * 
	 * @param isInLayoutPass
	 *            True if this was invoked from a layout pass, false otherwise.
	 */
	private void loadImageIfNecessary(final boolean isInLayoutPass) {
		final int width = getWidth();
		int height = getHeight();

		boolean isFullyWrapContent = getLayoutParams() != null
				&& getLayoutParams().height == LayoutParams.WRAP_CONTENT
				&& getLayoutParams().width == LayoutParams.WRAP_CONTENT;
		// if the view's bounds aren't known yet, and this is not a
		// wrap-content/wrap-content
		// view, hold off on loading the image.
		if (width == 0 && height == 0 && !isFullyWrapContent) {
			return;
		}

		// if the URL to be loaded in this view is empty, cancel any old
		// requests and clear the
		// currently loaded image.
		if (TextUtils.isEmpty(mUrl)) {
			if (mImageContainer != null) {
				mImageContainer.cancelRequest();
				mImageContainer = null;
			}
			setDefaultImageOrNull();
			return;
		}

		// if there was an old request in this view, check if it needs to be
		// canceled.
		if (mImageContainer != null && mImageContainer.getRequestUrl() != null) {
			if (mImageContainer.getRequestUrl().equals(mUrl)) {
				// if the request is from the same URL, return.
				return;
			} else {
				// if there is a pre-existing request, cancel it if it's
				// fetching a different URL.
				mImageContainer.cancelRequest();
				setDefaultImageOrNull();
			}
		}

		// The pre-existing content of this view didn't match the current URL.
		// Load the new image
		// from the network.
		ImageContainer newContainer = mImageLoader.get(mUrl,
				new ImageListener() {
					@Override
					public void onErrorResponse(VolleyError error) {
						if (mErrorImageId != 0) {
							setImageResource(mErrorImageId);
						}

						if (mObserver != null) {
							mObserver.onError();
						}
					}

					@Override
					public void onResponse(final ImageContainer response,
							boolean isImmediate) {
						// If this was an immediate response that was delivered
						// inside of a layout
						// pass do not set the image immediately as it will
						// trigger a requestLayout
						// inside of a layout. Instead, defer setting the image
						// by posting back to
						// the main thread.
						if (isImmediate && isInLayoutPass) {
							post(new Runnable() {
								@Override
								public void run() {
									onResponse(response, false);
								}
							});
							return;
						}

						int bWidth = 0, bHeight = 0;
						if (response.getBitmap() != null) {

							setImageBitmap(response.getBitmap());
							bWidth = response.getBitmap().getWidth();
							bHeight = response.getBitmap().getHeight();
							adjustImageAspect(bWidth, bHeight);

						} else if (mDefaultImageId != 0) {
							setImageResource(mDefaultImageId);
						}

						if (mObserver != null) {
							mObserver.onSuccess();

						}
					}
				});

		// update the ImageContainer to be the new bitmap container.
		mImageContainer = newContainer;

	}

	private void setDefaultImageOrNull() {
		if (mDefaultImageId != 0) {
			setImageResource(mDefaultImageId);
		} else {
			setImageBitmap(null);
		}
	}

	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		loadImageIfNecessary(true);
	}

	@Override
	protected void onDetachedFromWindow() {
		if (mImageContainer != null) {
			// If the view was bound to an image request, cancel it and clear
			// out the image from the view.
			mImageContainer.cancelRequest();
			setImageBitmap(null);
			// also clear out the container so we can reload the image if
			// necessary.
			mImageContainer = null;
		}
		super.onDetachedFromWindow();
	}

	@Override
	protected void drawableStateChanged() {
		super.drawableStateChanged();
		invalidate();
	}

	/*
	 * Adjusting imageview height
	 * */
	private void adjustImageAspect(int bWidth, int bHeight) {
		LinearLayout.LayoutParams params = (LayoutParams) getLayoutParams();

		if (bWidth == 0 || bHeight == 0)
			return;

		int swidth = getWidth();
		int new_height = 0;
		new_height = swidth * bHeight / bWidth;
		params.width = swidth;
		params.height = new_height;
		setLayoutParams(params);
	}
}

11. Open your layout for main activity (activity_main.xml) and add a list view element for the feed list.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:divider="@null" />

</LinearLayout>

12. Create another layout file named feed_item.xml under res ⇒ layout folder. This layout file represents each individual feed item row in the list view.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/feed_bg"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"

        android:layout_marginLeft="@dimen/feed_item_margin"
        android:layout_marginRight="@dimen/feed_item_margin"
        android:layout_marginTop="@dimen/feed_item_margin"
        android:background="@drawable/bg_parent_rounded_corner"
        android:orientation="vertical"
        android:paddingBottom="@dimen/feed_item_padding_top_bottom"
        android:paddingTop="@dimen/feed_item_padding_top_bottom" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingLeft="@dimen/feed_item_padding_left_right"
            android:paddingRight="@dimen/feed_item_padding_left_right" >

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/profilePic"
                android:layout_width="@dimen/feed_item_profile_pic"
                android:layout_height="@dimen/feed_item_profile_pic"
                android:scaleType="fitCenter" >
            </com.android.volley.toolbox.NetworkImageView>

            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingLeft="@dimen/feed_item_profile_info_padd" >

                <TextView
                    android:id="@+id/name"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:textSize="@dimen/feed_item_profile_name"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/timestamp"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:textColor="@color/timestamp"
                    android:textSize="@dimen/feed_item_timestamp" />
            </LinearLayout>
        </LinearLayout>

        <TextView
            android:id="@+id/txtStatusMsg"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="5dp"
            android:paddingLeft="@dimen/feed_item_status_pad_left_right"
            android:paddingRight="@dimen/feed_item_status_pad_left_right"
            android:paddingTop="@dimen/feed_item_status_pad_top" />

        <TextView
            android:id="@+id/txtUrl"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:linksClickable="true"
            android:paddingBottom="10dp"
            android:paddingLeft="@dimen/feed_item_status_pad_left_right"
            android:paddingRight="@dimen/feed_item_status_pad_left_right"
            android:textColorLink="@color/link" />

        <info.androidhive.listviewfeed.FeedImageView
            android:id="@+id/feedImage1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"
            android:scaleType="fitXY"
            android:visibility="visible" />
    </LinearLayout>

</LinearLayout>

13. Under data package, create a class named FeedItem.java. This is a POJO class used to create objects for each feed item while parsing the json. The feed item object contains information like profile pic, name, timestamp, status message, url and feed image.

package info.androidhive.listviewfeed.data;

public class FeedItem {
	private int id;
	private String name, status, image, profilePic, timeStamp, url;

	public FeedItem() {
	}

	public FeedItem(int id, String name, String image, String status,
			String profilePic, String timeStamp, String url) {
		super();
		this.id = id;
		this.name = name;
		this.image = image;
		this.status = status;
		this.profilePic = profilePic;
		this.timeStamp = timeStamp;
		this.url = url;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getImge() {
		return image;
	}

	public void setImge(String image) {
		this.image = image;
	}

	public String getStatus() {
		return status;
	}

	public void setStatus(String status) {
		this.status = status;
	}

	public String getProfilePic() {
		return profilePic;
	}

	public void setProfilePic(String profilePic) {
		this.profilePic = profilePic;
	}

	public String getTimeStamp() {
		return timeStamp;
	}

	public void setTimeStamp(String timeStamp) {
		this.timeStamp = timeStamp;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}
}

14. Now under adapter package create a class named FeedListAdapter.java. This is a custom adapter class for feed list view. This adapter class takes care following things.

> Displaying feed data like name, timestamp, profile pic, status message and feed image.
> Converts timestamp into x minutes/hours/days ago format
> Makes URL clickable by using url.setMovementMethod(LinkMovementMethod.getInstance())

package info.androidhive.listviewfeed.adapter;

import info.androidhive.listviewfeed.FeedImageView;
import info.androidhive.listviewfeed.R;
import info.androidhive.listviewfeed.app.AppController;
import info.androidhive.listviewfeed.data.FeedItem;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.text.Html;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.NetworkImageView;

public class FeedListAdapter extends BaseAdapter {	
	private Activity activity;
	private LayoutInflater inflater;
	private List<FeedItem> feedItems;
	ImageLoader imageLoader = AppController.getInstance().getImageLoader();

	public FeedListAdapter(Activity activity, List<FeedItem> feedItems) {
		this.activity = activity;
		this.feedItems = feedItems;
	}

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

	@Override
	public Object getItem(int location) {
		return feedItems.get(location);
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		if (inflater == null)
			inflater = (LayoutInflater) activity
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		if (convertView == null)
			convertView = inflater.inflate(R.layout.feed_item, null);

		if (imageLoader == null)
			imageLoader = AppController.getInstance().getImageLoader();

		TextView name = (TextView) convertView.findViewById(R.id.name);
		TextView timestamp = (TextView) convertView
				.findViewById(R.id.timestamp);
		TextView statusMsg = (TextView) convertView
				.findViewById(R.id.txtStatusMsg);
		TextView url = (TextView) convertView.findViewById(R.id.txtUrl);
		NetworkImageView profilePic = (NetworkImageView) convertView
				.findViewById(R.id.profilePic);
		FeedImageView feedImageView = (FeedImageView) convertView
				.findViewById(R.id.feedImage1);

		FeedItem item = feedItems.get(position);

		name.setText(item.getName());

		// Converting timestamp into x ago format
		CharSequence timeAgo = DateUtils.getRelativeTimeSpanString(
				Long.parseLong(item.getTimeStamp()),
				System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS);
		timestamp.setText(timeAgo);

		// Chcek for empty status message
		if (!TextUtils.isEmpty(item.getStatus())) {
			statusMsg.setText(item.getStatus());
			statusMsg.setVisibility(View.VISIBLE);
		} else {
			// status is empty, remove from view
			statusMsg.setVisibility(View.GONE);
		}

		// Checking for null feed url
		if (item.getUrl() != null) {
			url.setText(Html.fromHtml("<a href=\"" + item.getUrl() + "\">"
					+ item.getUrl() + "</a> "));

			// Making url clickable
			url.setMovementMethod(LinkMovementMethod.getInstance());
			url.setVisibility(View.VISIBLE);
		} else {
			// url is null, remove from the view
			url.setVisibility(View.GONE);
		}

		// user profile pic
		profilePic.setImageUrl(item.getProfilePic(), imageLoader);

		// Feed image
		if (item.getImge() != null) {
			feedImageView.setImageUrl(item.getImge(), imageLoader);
			feedImageView.setVisibility(View.VISIBLE);
			feedImageView
					.setResponseObserver(new FeedImageView.ResponseObserver() {
						@Override
						public void onError() {
						}

						@Override
						public void onSuccess() {
						}
					});
		} else {
			feedImageView.setVisibility(View.GONE);
		}

		return convertView;
	}

}

15. Now we have all the required classes in place. Open your main activity class MainActivity.java and add the following code. Here using volley JsonObjectRequest I fetched the json, parsed it(created array of feed item objects) and passed the data to list view adapter.

package info.androidhive.listviewfeed;

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.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ListView;

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;

public class MainActivity extends Activity {
	private static final String TAG = MainActivity.class.getSimpleName();
	private ListView listView;
	private FeedListAdapter listAdapter;
	private List<FeedItem> feedItems;
	private String URL_FEED = "https://api.androidhive.info/feed/feed.json";

	@SuppressLint("NewApi")
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

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

		feedItems = new ArrayList<FeedItem>();

		listAdapter = new FeedListAdapter(this, feedItems);
		listView.setAdapter(listAdapter);
		
		// These two lines not needed,
		// just to get the look of facebook (changing background color & hiding the icon)
		getActionBar().setBackgroundDrawable(new ColorDrawable(Color.parseColor("#3b5998")));
		getActionBar().setIcon(
				   new ColorDrawable(getResources().getColor(android.R.color.transparent)));

		// We first check for cached request
		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<JSONObject>() {

						@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);
		}

	}

	/**
	 * Parsing json reponse and passing the data to feed view list adapter
	 * */
	private void parseJsonFeed(JSONObject response) {
		try {
			JSONArray feedArray = response.getJSONArray("feed");

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

				FeedItem item = new FeedItem();
				item.setId(feedObj.getInt("id"));
				item.setName(feedObj.getString("name"));

				// Image might be null sometimes
				String image = feedObj.isNull("image") ? null : feedObj
						.getString("image");
				item.setImge(image);
				item.setStatus(feedObj.getString("status"));
				item.setProfilePic(feedObj.getString("profilePic"));
				item.setTimeStamp(feedObj.getString("timeStamp"));

				// url might be null sometimes
				String feedUrl = feedObj.isNull("url") ? null : feedObj
						.getString("url");
				item.setUrl(feedUrl);

				feedItems.add(item);
			}

			// notify data changes to list adapater
			listAdapter.notifyDataSetChanged();
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

Now run the project and test it once. Make sure that your emulator/device is having internet connect before you test.

Subscribe
Notify of
guest
625 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
erik suprayogi
erik suprayogi
6 years ago

Awesome

Jose Ricardo Dainese
Jose Ricardo Dainese
6 years ago

Dude, congratulations, this site has helped me a lot

ayajibo
ayajibo
6 years ago

Thanks man. This site helped me a lot. It is like everything I was looking for exists here.

Ravi Tamada
6 years ago
Reply to  ayajibo

You are welcome 🙂

Suumit Shah
Suumit Shah
6 years ago

This is damn awesome article Ravi! I wanted ask you one thing, is it possible to build such app which can fetch articles from some RSS feed and render same on screen?

Ravi Tamada
6 years ago
Reply to  Suumit Shah

Yeah, we can do. There is already a tutorial here, we need to do few tweaks like adding volley support. But I doubt about the feed banner image as rss feed doesn’t contains one.

http://www.androidhive.info/2012/05/android-rss-reader-application-using-sqlite-part-1/

Suumit Shah
Suumit Shah
6 years ago
Reply to  Ravi Tamada

I guess feed can contain images also, check this http://feeds.feedburner.com/techlitic 🙂

Ravi Tamada
6 years ago
Reply to  Suumit Shah

I think those images are from article content, there is no specific xml tag for it. May be we need to parse the html and get the images.

Suumit Shah
Suumit Shah
6 years ago
Reply to  Ravi Tamada

Ohh okay! Thanks for your prompt reply Ravi 🙂

Ravi Tamada
6 years ago
Reply to  Suumit Shah

You are welcome Suumit 🙂

Guest
Guest
6 years ago

I like your emulator. how to change it?

Ravi Tamada
6 years ago
Reply to  Guest

It’s not emulator, VLC player. Below app helped me to record my mobile screen and I played the video on PC.
https://play.google.com/store/apps/details?id=uk.org.invisibility.recordablefree

Zoloo
Zoloo
6 years ago

very good! i like your emulator. how to change it?

Ravi Tamada
6 years ago
Reply to  Zoloo

It’s not emulator, VLC player. Below app helped me to record my mobile screen and played the video on PC.
https://play.google.com/store/apps/details?id=uk.org.invisibility.recordablefree

Nehal Goyal
Nehal Goyal
6 years ago
Reply to  Ravi Tamada

hii
i want to combine slider menu and swipeable tab
i.e.. i want item A of slider menu has contain 2 tabs i.e. tab1 tab2…plzz help me..
i m using your tutorial for both of them..

Nagesh Kulkarni
Nagesh Kulkarni
6 years ago

Wow awesome, I really liked it…!!

krishnalalstha
krishnalalstha
6 years ago

How to show image in popup like facebook did ?

Ravi Tamada
6 years ago
Reply to  krishnalalstha

Create another activity with a NetworkImageView in it’s layout file.

Implement onClick listener on image on list view and pass the image url to full screen image view activity.

krishnalalstha
krishnalalstha
6 years ago
Reply to  Ravi Tamada

ya i know that but i want to achieve that kind of effect on click image. i hope you have noticed that effect.

Ravi Tamada
6 years ago
Reply to  krishnalalstha

Then you can have the networkimageview in the same layout below listview and do toggle hiding b/w listview and imageview. So that you can add any kind of effects while showing fullscreen image.

Filipe
Filipe
6 years ago
Reply to  krishnalalstha

You can achieve it using Rebound library https://github.com/facebook/rebound

baha_odeh
baha_odeh
6 years ago

thank you man , but i think loopj.com/android-async-http/ work better thank volley ?

Ravi Tamada
6 years ago
Reply to  baha_odeh

I haven’t tested, but I recommend volley as it is officially supported by android.com
https://developer.android.com/training/volley/index.html

Richard
Richard
6 years ago
Reply to  Ravi Tamada

Great guide! Thanks a lot. Btw what about robospice instead of volley?

Ravi Tamada
6 years ago
Reply to  Richard

I am hearing robospice for the the firsttime Richard

cost
cost
6 years ago

How can I “take” a real json file from facebook.com??? (real time facebook list)
That would be cool

Pedro Pedro
Pedro Pedro
6 years ago

hi Ravi, first of all I ‘ll like to thanks U for all the help you provide.I’ m a new android developper and your site is very helpfull.I would like to use the custom imageview you gave in a ViewPager, it works fine but the image isn’t displayed at the center how can I change it( the position of the image),Previously i did it in the XML layout.

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

can you paste your layout code here?

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

thank’s

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

what is com.brasserie.cap.adapters.fullscreenimageview?

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

it’s the same java class as the one you gave in your tutorial “FeedImageView” I only changed the method “adjustImageAspect” by adding

RelativeLayout.LayoutParams params = (android.widget.RelativeLayout.LayoutParams) getLayoutParams();

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

Try using LinearLayout.LayoutParams and use

params.gravity=Gravity.CENTER;

Also to display a fullscreen image we don’t have to create a custom imageview class. Use NetworkImageView directly in xml layout.

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

I’ve try it but i got an Exception
when i tried LinearLayout.params
java.lang.ClassCastException: android.widget.RelativeLayout$LayoutParams cannot be cast to android.widget.LinearLayout$LayoutParams, I think it is because the layout has a Relativelayout

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Pedro Pedro

yep fine,I did it as you said, change to linearlayout and I also modified my PageAdapter by overriding the “isViewFromObject” returning a linearlayout too.
thks a lot once more

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

I am glad you solved it 🙂

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

Sorry Ravi from disturbing once more 🙂 But I’m facing another matter once more 🙁
I would like to display a GIF image while downloading the image I put the image in the drawable folder, and use the “setDefaultImageResId” in my custom adapter, but the gif work as expected ,It behave like a normal Bitmap. I ‘ll like it to be as in your previous tuto on Volley. thks

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

In my volley tutorial, I used ProgressDialog element not GIF image. If you want to use gif image with animation use this library.
https://github.com/Hipmob/gifanimateddrawable

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

thks man I will try it 🙂

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

hi ravi, I’ve been around the Web and I found that sometimes displaying a GIF can cause an OOM exception, so i decided to use a progress bar( PB) while the image will be loading.I just added the PB in my layout then in the BaseAdapter class. I can show it but, how can I hide it once the download is done?

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

Which element you are using to display the image?

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

sorry I didn’t understand what U mean

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Pedro Pedro

If this could help I would like to display an Image while downloading, so I firstly planned to use a gif but I’m afraied of an OOM excep.so I would like to display a progress bar instead of that gif

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

Ok

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

I mean ImageView or NetworkImageView ?

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

I used the custom one U gave in this tutorial.

Ravi Tamada
6 years ago
Reply to  Pedro Pedro

Then it has callback methods onSuccess() and onError(). You can hide your PD in these methods.

.setResponseObserver(new FeedImageView.ResponseObserver() {
@Override
public void onError() {
// hide the PD here
}

@Override
public void onSuccess() {
// hide the PD here
}
})

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Ravi Tamada

thks man:) but I’ve tried your suggestion, in fact the real matter is how to show the PD, I would like to display it under the every single DefaultImage of my Custom Gridview , so the advice you gave me will hide it, but how to display the PD

Guest
Guest
6 years ago
Reply to  Pedro Pedro

I have been all the day looking how I can resolve that, but I didn’t found, If i didn’t hide the PD in the observer, it still display, but if I hide it, it doesn’t even display during the downloading with volley, it is normal it think.The only way to resolve it, it think I’m not sure, it will be if i could check if the default image is remplace by the one download, do U have an idea on how check it please.
thank’s

Pravesh Choudhary
Pravesh Choudhary
6 years ago

in my MainActivity.java, automatically MainActivity is extending ActionBarActivity and also appcompatv7 named folder is generating when I am creating the project which is not there in your code…why ?

Ravi Tamada
6 years ago

Its because you have updated your android SDK it to latest build tools version. You can revert your MainActivity to normal (like extending from activity), it will work. You can remove appcompatv7 too from build libraries.

I still need to study what ActionBarActivity is for, that’s why I posted this tutorial in older fashion.

Pravesh Choudhary
Pravesh Choudhary
6 years ago
Reply to  Ravi Tamada

can I send my project to you on facebook in .zip format so that you can make the correction ? I tried many times but I think there is some very small mistake.

Pravesh Choudhary
Pravesh Choudhary
6 years ago

Done successfully…found the problem !! Thanks ! 🙂

Ravi Tamada
6 years ago

Okay

Prathap
Prathap
6 years ago
Reply to  Ravi Tamada

ActionBarActivity is a class in AppCompat Library(from Android team) which is an extension of the support library designed to facilitate the use of the action bar design pattern across all versions of Android with a single API.

Similar to ActionBarSherlock Library.

Ravi Tamada
6 years ago
Reply to  Prathap

Thanks Prathap for the info 🙂

Guest
Guest
6 years ago

Hello ravi sir ! this is a very useful tutorial ! thankyou soo much !
can you plz tell is there any short way to run this in a fragment and not in an activity ?
waiting for your reply !

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Guest

hi! your fragment is for the listView? normally there is no great difference

Guest
Guest
6 years ago
Reply to  Pedro Pedro

please elaborate the method to show this Custom ListView Feed into a fragment 🙂
regards

Pedro Pedro
Pedro Pedro
6 years ago
Reply to  Guest

first of all you will need create another activity, which will contain your fragment,
and the main activity (the one which ravi gave in this tutorial) you change
it to fragment that means it will extend Fragment or Listfragment as you like
You will have to do some changes in your code because the fragment do not react the same as activity
I hope U get what I mean(french speaker and android’s newby so 🙂 )

Omer Rosenbaum
6 years ago

Hi Ravi,
Is this feed dynamic, that is, uploading the latest post from every feed?
As far as I can see it is set to certain links. Is there a way to set it to websites’ RSS feed?

Ravi Tamada
6 years ago
Reply to  Omer Rosenbaum

No its not dynamic. You can write some logic to parse the RSS feed and display the feed in this fashion or you can do the same on server side and give the json to mobile.

may be this helps you
http://www.androidhive.info/2012/05/android-rss-reader-application-using-sqlite-part-1/

Subhendu Pratap Singh
Subhendu Pratap Singh
6 years ago

Hi Ravi,
Yet another amazing post for all the android enthusiasts. Double thumbs up to your post.
One small thing, i think layout height should be fill parent in activity_main.xml otherwise in case of single item in the list view, image doesn’t show up properly.

Ravi Tamada
6 years ago

Hmm, I didn’t think about it. Thanks for the suggestion.

IMRAN
IMRAN
6 years ago

Thanks Ravi Tamada …………. i have a simple query …. can i upload file using “volley” .

IMRAN
IMRAN
6 years ago
Reply to  Ravi Tamada

Thanks for your quick reply……… Ravi which is the best way to upload large size files to server .

Ravi Tamada
6 years ago
Reply to  IMRAN

Actually when file is larger (lets say 30MB), we can’t upload the file directly as it can’t fit into memory. So we need to do a streaming upload where on the server you should have a mechanism to accepts chunks of file and do the appending process to create a complete file.

Guest
Guest
6 years ago
Reply to  Ravi Tamada

what if file size not more than 5mb

IMRAN
IMRAN
6 years ago
Reply to  Ravi Tamada

what if file size not more than 5mb, which is the best way to upload files to server

Ravi Tamada
6 years ago
Reply to  IMRAN

Use volley or apache http clients

IMRAN
IMRAN
6 years ago
Reply to  Ravi Tamada

Thanks Ravi

badname
badname
6 years ago

what this format ? “timeStamp”: “1403375851930”,
how i insert now ?
14 year ?
pls help for insert this true 🙂

Ravi Tamada
6 years ago
Reply to  badname

It is linux time stamp. You can generate it easily in java.

badname
badname
6 years ago
Reply to  Ravi Tamada

thx man
also feed.json not raed from my host i fix it now with “?” 🙂
url…”………com/file/feed.json?”

Ravi Tamada
6 years ago
Reply to  badname

OK

Faiz
Faiz
6 years ago

Really it is great site. I am learning android. It will be great if you can write new article to demonstrate RSS using volley capabilities.

Thanks in advance

Ravi Tamada
6 years ago
Reply to  Faiz

Hi Faiz, I already have an article about RSS reader. May be you can try integrating volley in the app.
http://www.androidhive.info/2012/05/android-rss-reader-application-using-sqlite-part-1/

Faiz
Faiz
6 years ago
Reply to  Ravi Tamada

I will try,
Thanks a lot Ravi

Lubulwa Ric
Lubulwa Ric
6 years ago

Ravi thanks for the post, how can i use this volley library to retrieve articles from any website and this information should be updated as the website gets updated

Ravi Tamada
6 years ago
Reply to  Lubulwa Ric
Lubulwa Ric
Lubulwa Ric
6 years ago
Reply to  Ravi Tamada

Thanks for the reply but some sites do not have rss url, i was thinking, can this library work like jsoup that just scans the page source code and retrieves articles?

Ravi Tamada
6 years ago
Reply to  Lubulwa Ric

Yes that would be another solution but I am not sure how you will manage to write a parser for multiple sites as not all of them follows the same html structure.

jorge david
jorge david
6 years ago

thank you man, i’m making an university project and it help me a lot.

Ravi Tamada
6 years ago
Reply to  jorge david

you are welcome 🙂

IMRAN
IMRAN
6 years ago

Ravi i want to ask a question which is not relevant ………any idea how we can develop app like “WhatsApp”……… thanks

Ravi Tamada
6 years ago
Reply to  IMRAN

I can’t say it in one sentence. Lot of things involves like REST API, server side database, GCM.

IMRAN
IMRAN
6 years ago
Reply to  Ravi Tamada

Ravi i already worked with REST API, server side database(MySQL , MSSQL), GCM
but as per my experience ….i think …we can’t develop IM app with these as fast as “whatsApp” or “viber”

Ravi Tamada
6 years ago
Reply to  IMRAN

No, we can develop.I developed a prototype a long time back, but couldn’t post on blog as it is somewhat lengthy article.

André
André
6 years ago
Reply to  Ravi Tamada

Any way we can see the code?

Ravi Tamada
6 years ago
Reply to  André

Sorry, I don’t have it right now.

IMRAN
IMRAN
6 years ago
Reply to  Ravi Tamada

i am learning lot of things from your bog …… have you any platform where we can put our queries .
Thanks

Tuan Hoang Anh
Tuan Hoang Anh
6 years ago

please help me, i use stringrequest of volley library with VietNam language from web, after response my result error font. Any solution?

Mehrdad Garebaghi
6 years ago

hi ravi

just a question

i want to make an rss app to save sqlite db with this method and i only have a question

how does the app knows if the json feed is updated?

FYI the app should update automatic when user opens it

i figured that i can compare the id of last data i added to db with the first id of what is being parsed from json

is it ok or there is a better way other than that?

jorge david
jorge david
6 years ago

i have a question, how can use this with fragments?, i mean that a fragment content a listview

Bala Vishnu
Bala Vishnu
6 years ago
Reply to  jorge david

Its almost the same, Put the contents of the onCreate() in MainActivity to onActivity Created() of a fragment and then place the fragment on top of an Activity

Ravi Tamada
6 years ago
Reply to  Bala Vishnu

Thanks Bala 🙂

akin
akin
6 years ago

hello Ravi, You have been doing a great work here. Most of what I can do on android was from android hive. But Please i want you to make a tutorial on User profiles. where a user logs in and uploads his/her picture, post articles and also comment on another user’s article. hope am not asking too much…… am an oliver twist.

Ravi Tamada
6 years ago
Reply to  akin

Hi akin,

You requirement is not simple. It needs lot of things to be integrated in one project. Following will help you

http://www.androidhive.info/2012/05/how-to-connect-android-with-php-mysql/ (server client connectivity)
http://www.androidhive.info/2014/05/android-working-with-volley-library-1/ (for json parsing)

Rajesh Jaiswal
Rajesh Jaiswal
6 years ago

Wowww!!! What a blog.

Awesome… Everything is working fine

Thanks

Ravi Tamada
6 years ago
Reply to  Rajesh Jaiswal

Thanks for the appreciation.

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

thank you sir , its working like a charm.
i am able to upload my file using filezila And CAN parse json also from my json url.

sir you are great , first nd last resort for many android app developer.

silentmind
silentmind
6 years ago
Reply to  Rajesh Jaiswal

ravi’s magic

Ravi Tamada
6 years ago
Reply to  silentmind

🙂

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

ravi sir please help me out

i don’t know how to parse my own json file in my app

i purchased domain name and hosting also

but i don’t know how to upload json file and you have api.androidhive…….
this url , i don’t how to get api.mywebsite…..
please help me out .

Ravi Tamada
6 years ago
Reply to  silentmind

Which hosting you bought?

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

sir , i have bought it from godaddy , i have cpanel also .

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

sir i have of godaddy , with that i have cpanel also.

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

i have of godaddy , with which i got cpanel also.

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

i have hosting godaddy and i have cpanel also

Ravi Tamada
6 years ago
Reply to  silentmind

Then to upload a file you need to follow these steps.
1. Create an FTP user in cpanel
2. Download filezilla software to connect to ftp
3. After connecting through filezilla upload your json file www folder (it might changes depending on your server)
4. Access the file via url in browser

If you want to access like me i.e api.yourdomain, you need to create a subdomain in godday’s admin panel. Create a new cRecord.

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

sir you are great , i am gonna try this .
thanks a lot.

Bodo Riffer
Bodo Riffer
6 years ago

Hello!

This really is a great article. I would like to download the source but have no afford in registering with android hive. Tried 4 times by now but do not get any email. Maybe a permanent problem?

youming2007
youming2007
6 years ago
Reply to  Bodo Riffer

You just need to type your email when downloading and click Download Code again!

Ravi Tamada
6 years ago
Reply to  Bodo Riffer

Yeah, I have noticed it. Please check your SPAM folder. It should be there.

PISOT
PISOT
6 years ago

Ravi, How can I put the json request inside my model class? Hoping for your response

Ravi Tamada
6 years ago
Reply to  PISOT

What do you mean by keeping json request in model class. Could you elaborate?

amin
amin
6 years ago

Hi Ravi, could you make an tutorial to how to create a messenger program like viber, line , what app or…. ? your works are so nice, thanks.

Ravi Tamada
6 years ago
Reply to  amin

Yeah, I am preparing it. But in order to post that I have to cover lot of other topics first.

IMRAN
IMRAN
6 years ago
Reply to  Ravi Tamada

great ………… we are waiting Ravi

silentmind
silentmind
6 years ago
Reply to  Ravi Tamada

eagerly waiting

Lewis Munene
Lewis Munene
6 years ago

how do you produce that timestamp?

Nikhil Shete
Nikhil Shete
6 years ago

Thanx for this tutorial. I want to refresh or update feed items of the list view. Refresh button click. i used //Calendar calendar = Calendar.getInstance();

//long serverDate = AppController.getInstance().getRequestQueue().getCache().get(URL_FEED).serverDate;

//AppController.getInstance().getRequestQueue().getCache().invalidate(URL_FEED, true);

//AppController.getInstance().getRequestQueue().getCache().remove(URL_FEED);

Nothing works. Works only when go to app setting and clear cache. Please help me

Ibrahim Mubarak
6 years ago
Reply to  Nikhil Shete

Simple fix is to replace

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);
}
}

with

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);
}

this will however remove the benefits of having cache.
To effectively use cache you need to implement

private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}

and call isNetworkAvailable() in onCreate such that

if(isNetworkAvailable()){
//the Call for server comes here
}
else{
//Call the cache here
}

I hope you can figure it out. If not, I’ll try to explain further

Nikhil Shete
Nikhil Shete
6 years ago

thanks. But how refresh dynamically like facebook. and how check feed data is valid or not. i tried changing data from jason doesnt change quickly into app feed. Need dynamic list like fb

Ibrahim Mubarak
6 years ago
Reply to  Nikhil Shete

I’m sure you’ll need to use GCM fot that.However i’m not very well versed with GCM yet and you’ll need to figure out the code yourself.
http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/

ketul
ketul
6 years ago

Hi Ravi,

This is really good article and I want to use in my porject and for that I try to modify it,
I have tried to change Feedimage to view pager with dynamic height like facebook but i stuck and its not working, can you help me to solve out this.

Thanks

Z
Z
6 years ago

hi Ravi, i just want to display list of imageview and if i click one the selected imageview will zoom.
how can i do that?
thanks 🙂

JAmes
JAmes
6 years ago

How do you force it to refresh the feed each time on load not load from cache.

nana
nana
6 years ago

Ravi i downloaded the source code and tried running the apk file in the bin folder…but it is not working

EmileH2000
EmileH2000
6 years ago

Hi Ravi I really appreciate how you help all of us with these tutorials. I’m a young coder (16) and want to know how i can refresh this feed, or better still, how can i make it auto refresh itself like facebook does?

Ravi Tamada
6 years ago
Reply to  EmileH2000

Hi Emile,

May be you need to make a call to server on onResume() method to get latest feed. You need to have a server side mechanism to change the expiry headers, otherwise volley won’t fetch updated json from the url.

EmileH2000
EmileH2000
6 years ago
Reply to  Ravi Tamada

Ok thanks!

saeed
saeed
6 years ago
Reply to  Ravi Tamada

how can i do it ?

Charbel Hassrouny
Charbel Hassrouny
6 years ago

Hey, i created Android Sliding Menu (it is done by androidhive also, http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/)
this thing is that each item in this Sliding Menu calls a fragment, i want to make one of the fragments calls this listview feed.
Can i have a clear code of how to convert this to fragment, not fragment activity.

Thanks in advance 😀

Alan Lee
Alan Lee
6 years ago

I trying do this combination, and also get error, maybe :disqus can give a hint to us 🙂

uno_xx
uno_xx
6 years ago
Reply to  Alan Lee

I am using it inside a fragment without any problem. May be you missed something.

Alan Lee
Alan Lee
6 years ago
Reply to  uno_xx

Yeap, I already found the problem and fixed it, thx 🙂

nishant
nishant
6 years ago
Reply to  Alan Lee

Could u plz tell me?

uno_xx
uno_xx
6 years ago
Reply to  nishant

Code is almost same, except for using getActivity() as context.

nishant
nishant
6 years ago
Reply to  uno_xx

Thanks.
I’ve fragment class (as in case of navigation drawer ) that calls my simple layout .
Do I need to create new activity for placing above given MainActivity code or I can place it into
Existing fragment class. Wht changes I’ve to make?

I’m kind of new here ….plz help. here is my mail id : nishant2740@gmail.com

uno_xx
uno_xx
6 years ago
Reply to  nishant

I tried it in same fragment but there are many possibilities.

nishant
nishant
6 years ago
Reply to  uno_xx

Thanks again.
Can u send me that fragment class coding which u have done for ?if possible.

uno_xx
uno_xx
6 years ago
Reply to  nishant
nishant
nishant
6 years ago
Reply to  uno_xx

I’ve implemented the given code But I’m getting unfortunately app_name has stopped.l
Any correction…..!

uno_xx
uno_xx
6 years ago
Reply to  nishant

You have to find the problem yourself, you have logs, you have code. Take help from logs and try to solve it…

nishant
nishant
6 years ago
Reply to  uno_xx

Can u share ur idea!!.?? Please.

Tanmay
Tanmay
6 years ago

how to fetch data from the website(which do not have rss feed or json feed in their website) in the same example u mention above ?
and news feed should update automatically with the website posts and data with time to time

Charbel Hassrouny
Charbel Hassrouny
6 years ago

how can i get the FeedItem id at a specific position in the list?

Lewis Munene
Lewis Munene
6 years ago

i used the name textview to get a specific position .in the FeedlistAdapter under the get view method i added this …
final FeedItem item = feedItems.get(position);

name.setText(item.getName());

name.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
info =item.getName();
Bundle extras = new Bundle();
Intent i1 = new Intent (context, Begin.class);
extras.putString(“val”, info);
//pasing info to new activity
i1.putExtras(extras);
context.startActivity(i1);

//Intent callIntent = new Intent();
Log.d(“Clicked”,”textview clicked “

jeeva
jeeva
6 years ago

Whenever i update the json file in my server,application not showing the updated data,

it shows the updated data only if i reinstall the application ,Kindly share the code for this issue and also include loading alert dialog box

Mehmet Can Taş
Mehmet Can Taş
6 years ago
Reply to  jeeva

I need that too

Kelvin
Kelvin
6 years ago

I am trying to redo the whole project using fragments instead of activity but there is an error at feedlistadapter.java trying to get the layout inflater for fragments

max
max
6 years ago

how to make infinity scroll ?

Guest
Guest
6 years ago

It is very good indeed but how do you parse JSON in UTF-8 ? In order to display Hindi 🙂 I am making an app which is Hindi related.
Thank you very much if you have time to explain or add the few line of code which would make it possible to display it properly.

Tonyoh87
Tonyoh87
6 years ago

Great Tutorial 🙂

Ravi Tamada
6 years ago
Reply to  Tonyoh87

Thank you.

TonyAndroid
TonyAndroid
6 years ago

I can’t download the code (keep getting timeout). Does anyone mind send me the code, please?
my mail: raffproject@gmail.com

Ravi Tamada
6 years ago
Reply to  TonyAndroid

Please check your SPAM folder for activation email.

wellington
wellington
6 years ago
Reply to  Ravi Tamada

Also I can not download

Nef
Nef
6 years ago

Excellent tutorial congratulations. I have a question. How can I show
the content within a fragment?. I hope to have your help. Thank you

JustHit Play
JustHit Play
6 years ago

Hi I try this onw but my app says unfortunately stop… Can you please help me..

Bas Wilson
Bas Wilson
6 years ago
Reply to  JustHit Play

Anyone Found a fix yet?

JustHit Play
JustHit Play
6 years ago

Hi Ravi.. I wonder if I can use my own facebook URL in the json? and how?

Ravi Tamada
6 years ago
Reply to  JustHit Play

I haven’t tried. But look for graph api in facebook docs.

JustHit Play
JustHit Play
6 years ago
Reply to  Ravi Tamada

Hi Ravi… This is what I found and Tried. But, the app loads a blank feed. What Am I doing wrong?

———–

“How to obtain JSON/RSS feed for Facebook Pages without OAuth/GraphAPI

Facebook killed their publicly available RSS feed for Facebook Pages couple of years back in favor of their walled garden approach (GraphAPI). For example, if you go to http://graph.facebook.com/Nike/feed it will ask you for a valid access token which you can get obtain via OAuth Authorization which entails quite a few steps. If you just wanted to display/parse any Facebook Page feed without going through those hoops you are out of luck!

I found myself in a similar situation recently and after some Googling I was able to figure out a workaround. Here’s how it goes:

1) Go to https://developers.facebook.com/tools/explorer

2) Put the username/vanity url of the Facebook Page in question in the request bar and hit Submit. For example, if you wanted to get a feed for:https://www.facebook.com/nike you would put “nike” without quotes in the request bar and click on Submit. (Make sure GET request is selected in the drop-down)

3) Grab the id from the results below and paste it in this URL: https://www.facebook.com/feeds/page.php?id=%5BFACEBOOK-ID-GOES-HERE%5D&format=%5Brss20|json]
So for example, if we wanted JSON feed for Nike’s Facebook page, we’d go to:https://www.facebook.com/feeds/page.php?id=15087023444&format=json

————–

Here is my code:

e String URL_FEED = “https://www.facebook.com/feeds/page.php?id=15087023444&format=json”;

and here is my error:

[2014-07-30 21:06:07 – Facebook Like FeedView] ActivityManager: Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=info.androidhive.listviewfeed/.MainActivity }

[2014-07-30 21:06:07 – Facebook Like FeedView] ActivityManager: Warning: Activity not started, its current task has been brought to the front

Bas Wilson
Bas Wilson
6 years ago
Reply to  JustHit Play

I also have this problem blank feed, can anyone help?

JustHit Play
JustHit Play
6 years ago
Reply to  Bas Wilson

yeah same problem ! I hope :disqus help us..

Ravi Tamada
6 years ago
Reply to  JustHit Play

Please try to write the response to LogCat and verify whether you guys are getting something in the response or not. This happened to me when my phone doesn’t have internet connection.

JustHit Play
JustHit Play
6 years ago
Reply to  Ravi Tamada

Im using Emulator..

Ravi Tamada
6 years ago
Reply to  JustHit Play

Did you printed the response to logcat? I already printed in log. Check for “Response: ” or “Error: ”

VolleyLog.d(TAG, “Response: ” + response.toString()); will print the json added in MainActivity.java

JustHit Play
JustHit Play
6 years ago
Reply to  Ravi Tamada

the error: Error Opening trace file: No such file or directory (2)

Ravi Tamada
6 years ago
Reply to  JustHit Play

Its not the error. Paste the complete log if you see it in red color font.

JustHit Play
JustHit Play
6 years ago
Reply to  Ravi Tamada

what i did is i change your json link

http://api.androidhive.info/feed/feed.json to

“https://www.facebook.com/feeds/page.php?id=196934133652011&format=json”

Ravi Tamada
6 years ago
Reply to  JustHit Play

It won’t work that way for every json url. You need to make the changes in the code according to the json response.

JustHit Play
JustHit Play
6 years ago
Reply to  Ravi Tamada

Can you help me to figure this out ?

Guest
Guest
6 years ago

Hi Ravi, I have succesfully build the app and done everything without errors and stuff but now on my phone on start up of the app it says: Unfortunately, “My App” Has Stopped. Can you suggest anything to fix this?

Ravi Tamada
6 years ago
Reply to  Guest

Pls check your Logcat for errors.

Guest
Guest
6 years ago
Reply to  Ravi Tamada

The red lines in the logcat starts with FATAL EXCEPTION: main, Hope you can help me, and maybe a crucial one is: Process”” com.example.listviewfeed, PID: 32486

Guest
Guest
6 years ago
Reply to  Guest

I Have fixed thanks anyway

Bas Wilson
Bas Wilson
6 years ago
Reply to  Ravi Tamada

Hi Ravi, How can i use a custom json file I have uploaded it to my website and when i go to the link its the same as how yours would preview but when i put the link in MainActivity.java and if i then start the app nothing shows up.. Can you help please

Ibrahim Mubarak
6 years ago

I Have updated the project to download new information everytime the activity is loaded and internet connection is available.
When internet connection is not available it fetches the cache and uses it.
You can also combine this with refresh options like SwipeRefreshLayout or the ActionBar Refresh Button [Not Included in this project]. whenever you want to refresh just call getFeed();
Download: http://go.adm.bugs3.com/1

Faiz
Faiz
6 years ago

Thanks a lot for your valuable contribution…. need a solution for xml request instead of json

Ibrahim Mubarak
6 years ago
Reply to  Faiz

final String URL = “/volley/resource/recent.xml”;
StringRequest req = new StringRequest(URL, new Response.Listener() {
@Override
public void onResponse(String response) {
VolleyLog.v(“Response:%n %s”, response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.e(“Error: “, error.getMessage());
}
});

// add the request object to the queue to be executed
ApplicationController.getInstance().addToRequestQueue(req);

parse XML in onResponse.You can find tutorial for it in this blog itself

Jeeva
Jeeva
6 years ago

Hi , i have used your updated code from your download path, but the application is not refresing everytime when i update the json file in the server, kindly help me. you can also reach me at jeevap14@gmail.com

Ibrahim Mubarak
6 years ago
Reply to  Jeeva

What do you mean?
Does it not load new data instantly the server was updated or it doesn’t update itself even during activity launch?
Keep in mind that for information to be updated instantly you need to use GCM

Jeeva
Jeeva
6 years ago

Hi Idragon81, it doesn’t update itself even during activity launch, it only refresh only when i clear the cache.Kindly check and provide me the solution

Indra
Indra
6 years ago

Link is not working Pls update

Levi Costa
Levi Costa
6 years ago

Link not work.. 🙁

625
0
Would love your thoughts, please comment.x
()
x