Download and Display Image in Android GridView

LinkedIn
Hacker News

This example is an improved version of my previous example Android GridView Example. Instead of using static images to display the grid items, lets make this example more realistic by downloading the data in realtime from server and render the grid items. The following video depicts the output of this example.

Without wasting much time, let us jump straight into what it takes to build this kind of GridView. You need to follow the following steps to complete this example.

-Advertisement-

1. Add GridView in Activity Layout

First, create a new android project. For this example, I prefer to use Android Studio. Create a new layout file to your project res/layout folder and name it as activity_grid_view.xml. And add the following code blocks.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#f0f0f0">

    <GridView
        android:id="@+id/gridView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:columnWidth="100dp"
        android:drawSelectorOnTop="true"
        android:gravity="center"
        android:numColumns="auto_fit"
        android:stretchMode="columnWidth"
        android:verticalSpacing="5dp"
        android:focusable="true"
        android:clickable="true"/>

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/progressBar"
        android:layout_centerInParent="true"
        android:visibility="gone"/>
</RelativeLayout>

The above layout is pretty straight forward. We have declared an GridView and a ProgressBar in activity layout. The progress bar will be displayed when the data is being downloaded.

2. Declare GridView Item Layout

Let us now add another file named grid_item_layout.xml to res/layout folder. This layout will be used by custom grid adapter for laying out individual grid item. For the sake of simplicity, we are adding an ImageView and a TextView.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="5dp"
    android:background="@drawable/grid_color_selector"
    android:orientation="vertical"
    android:padding="5dp">

    <ImageView
        android:id="@+id/grid_item_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="centerCrop"/>

    <TextView
        android:id="@+id/grid_item_title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center"
        android:maxLines="2"
        android:ellipsize="marquee"
        android:textSize="12sp" />

</LinearLayout>

3. Adding Internet Permission

You might be aware that, Android application must declare all the permissions that are required for application. As we need to download the data form server, we need to add the INTERNET permission. Add the following line to AndroidManifest.xml file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.javatechig.gridviewexample">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".GridViewActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity android:name=".DetailsActivity" />
    </application>

</manifest>

Notice that we have also declared all the activities used in the application.

4. Adding Picasso Image Downloading Library

Android open source developer community brings some of the interesting libraries that can be integrated easily to Android applications. They serves a great deal of purpose and saves lot of time. Here in this example, I am talking about Picasso image loading library. We will add Picasso library for downloading and caching of images. Visit here to learn more about how to use Picasso library in Android.

You can add the Picasso library by adding the following dependency to the build.gradle file.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.squareup.picasso:picasso:2.5.2'
}

5. Create a GridView Custom Adapter

A grid view is an adapter view. It requires an adapter to render the collection of data items. Add a new class named GridViewAdapter.java to your project and add the following code snippets.

package com.javatechig.gridviewexample;

import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;

public class GridViewAdapter extends ArrayAdapter<GridItem> {

    private Context mContext;
    private int layoutResourceId;
    private ArrayList<GridItem> mGridData = new ArrayList<GridItem>();

    public GridViewAdapter(Context mContext, int layoutResourceId, ArrayList<GridItem> mGridData) {
        super(mContext, layoutResourceId, mGridData);
        this.layoutResourceId = layoutResourceId;
        this.mContext = mContext;
        this.mGridData = mGridData;
    }


    /**
     * Updates grid data and refresh grid items.
     * @param mGridData
     */
    public void setGridData(ArrayList<GridItem> mGridData) {
        this.mGridData = mGridData;
        notifyDataSetChanged();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        ViewHolder holder;

        if (row == null) {
            LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new ViewHolder();
            holder.titleTextView = (TextView) row.findViewById(R.id.grid_item_title);
            holder.imageView = (ImageView) row.findViewById(R.id.grid_item_image);
            row.setTag(holder);
        } else {
            holder = (ViewHolder) row.getTag();
        }

        GridItem item = mGridData.get(position);
        holder.titleTextView.setText(Html.fromHtml(item.getTitle()));

        Picasso.with(mContext).load(item.getImage()).into(holder.imageView);
        return row;
    }

    static class ViewHolder {
        TextView titleTextView;
        ImageView imageView;
    }
}

Notice the following in the above code snippets,

  • The setGridData() method updates the data display on GridView.
  • The Picasso.with().load() method is used to download the image from url and display on image view.
  • The GridViewAdapter class constructor requires the id of the grid item layout and the list of data to operate on.
  • You might be surprised, where is the GridItem class came from. Its not a magic, we need to add GridItem.java class to our project.  The GridItem class looks as follows.

6. Download Data and Hook it to Activity

Now we will be heading towards hooking the adapter to GridView and make it functional. Create a new Java class and name it as GridViewActivity.java and perform the following steps.

  • Override the onCreate() method and set the layout by calling setContentView() method
  • Initialize the GridView and ProgressBar component by using their declared layout id.
  • Initialize the CustomGridView adapter by passing the grid row layout id and the list of GridItem objects.
  • Use AsyncTask to download data from server, once download is successful read the stream JSON response.
  • Parse the JSON string into the list of GridItem objects. Once downloading and parsing is completed, in onPostExecute() callback update the UI elements.

The following code does all the above steps as described. Add the following code to GridViewActivity class.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.Toast;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class GridViewActivity extends ActionBarActivity {
    private static final String TAG = GridViewActivity.class.getSimpleName();
    private GridView mGridView;
    private ProgressBar mProgressBar;
    private GridViewAdapter mGridAdapter;
    private ArrayList<GridItem> mGridData;
    private String FEED_URL = "http://stacktips.com/?json=get_recent_posts&count=45";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gridview);

        mGridView = (GridView) findViewById(R.id.gridView);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);

        //Initialize with empty data
        mGridData = new ArrayList<>();
        mGridAdapter = new GridViewAdapter(this, R.layout.grid_item_layout, mGridData);
        mGridView.setAdapter(mGridAdapter);

        //Start download
        new AsyncHttpTask().execute(FEED_URL);
        mProgressBar.setVisibility(View.VISIBLE);
    }

    //Downloading data asynchronously
    public class AsyncHttpTask extends AsyncTask<String, Void, Integer> {

        @Override
        protected Integer doInBackground(String... params) {
            Integer result = 0;
            try {
                // Create Apache HttpClient
                HttpClient httpclient = new DefaultHttpClient();
                HttpResponse httpResponse = httpclient.execute(new HttpGet(params[0]));
                int statusCode = httpResponse.getStatusLine().getStatusCode();

                // 200 represents HTTP OK
                if (statusCode == 200) {
                    String response = streamToString(httpResponse.getEntity().getContent());
                    parseResult(response);
                    result = 1; // Successful
                } else {
                    result = 0; //"Failed
                }
            } catch (Exception e) {
                Log.d(TAG, e.getLocalizedMessage());
            }
            return result;
        }

        @Override
        protected void onPostExecute(Integer result) {
            // Download complete. Let us update UI
            if (result == 1) {
                mGridAdapter.setGridData(mGridData);
            } else {
                Toast.makeText(GridViewActivity.this, "Failed to fetch data!", Toast.LENGTH_SHORT).show();
            }
            mProgressBar.setVisibility(View.GONE);
        }
    }

    String streamToString(InputStream stream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stream));
        String line;
        String result = "";
        while ((line = bufferedReader.readLine()) != null) {
            result += line;
        }

        // Close stream
        if (null != stream) {
            stream.close();
        }
        return result;
    }

    /**
     * Parsing the feed results and get the list
     * @param result
     */
    private void parseResult(String result) {
        try {
            JSONObject response = new JSONObject(result);
            JSONArray posts = response.optJSONArray("posts");
            GridItem item;
            for (int i = 0; i < posts.length(); i++) {
                JSONObject post = posts.optJSONObject(i);
                String title = post.optString("title");
                item = new GridItem();
                item.setTitle(title);
                JSONArray attachments = post.getJSONArray("attachments");
                if (null != attachments && attachments.length() > 0) {
                    JSONObject attachment = attachments.getJSONObject(0);
                    if (attachment != null)
                        item.setImage(attachment.getString("url"));
                }
                mGridData.add(item);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

At this point you will be able to run the app and notice that the app will download the data from the server and display on GridView.

7. Handle GridView Click Event

Right now GridView is not responding to user clicks. Let us make it more functional by adding the following code.

mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {

		//Get item at position
		GridItem item = (GridItem) parent.getItemAtPosition(position);

		//Pass the image title and url to DetailsActivity
                Intent intent = new Intent(GridViewActivity.this, DetailsActivity.class);
                intent.putExtra("title", item.getTitle());
                intent.putExtra("image", item.getImage());

		//Start details activity
		startActivity(intent);
	}
});

When user clicks on a grid item, we will start another activity that displays the full screen image. You can start one activity form another by calling startActivity() method.

We need to pass the details of the item such as title, and image url for displaying it on DetailsActivity.

8. Create Details Activity Layout

Add a new layout file to res/layout directory, name it as activity_details_view.xml and add the following code snippets.

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

    <ImageView
        android:id="@+id/grid_item_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:scaleType="fitCenter" />

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:background="#00000c"
        android:padding="10dp"
        android:textColor="#fff"
        android:textSize="20dp" />
</FrameLayout>

9. Completing the Details Activity

The DetailsActivity retrieves the details passed from GridViewActivity and renders the details on screen. Create a new class named DetailsActivity and add the following code snippets.

package com.javatechig.gridviewexample;

import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.text.Html;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;

public class DetailsActivity extends ActionBarActivity {
    private TextView titleTextView;
    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_details_view);

        ActionBar actionBar = getSupportActionBar();
        actionBar.hide();

        String title = getIntent().getStringExtra("title");
        String image = getIntent().getStringExtra("image");
        titleTextView = (TextView) findViewById(R.id.title);
        imageView = (ImageView) findViewById(R.id.grid_item_image);
        titleTextView.setText(Html.fromHtml(title));

        Picasso.with(this).load(image).into(imageView);
    }
}

10. Download Complete Example

Download

11. Custom Activity Transition in GridView

Continue reading in our next tutorial.

Tagged in : AdapterGridView

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.
  • Shyam Zawar

    can you please send the php code for this

  • Zeesha

    it’s just a model class

    public class GridItem {

    String title,image;

    public String getTitle() {

    return title;

    }

    public void setTitle(String title) {

    this.title = title;

    }

    public String getImage() {

    return image;

    }

    public void setImage(String image) {

    this.image = image;

    }

    }

  • Roberto Tomás

    nice toot… how do you scroll to a specific item in that?

  • A – Kay Qureshi

    how to fix this error …. plz tell me……!

  • akhil

    Dear Nil
    I need Json Script Code can you share it with me .I shall be very obliged to u.

  • Patient Baïse

    Hi,

    Nilanchala

    I use the code but in some items I can not get the images.
    Can I know why?
    This is a problem of size jpg or png format?
    And also I can not have more than 10 items. What should I do?
    Thank you

  • Ammar

    could you please share your server side code as well. i want to see how can we get the images and text from our database?

  • Madson Gr

    When I open some images from de gridview they get stuck at the top of the layout. I am using PhotoviewAttacher to zoom them on double tap. Only when I double tap the image it goes to its right position in the middle of the layout. What is this?

  • Madson Gr

    could you please post your php file? I have some problems with “Value posts of type java.lang.String cannot be converted to JSONObject” because I don´t want the title. Just made json print images url

  • renji

    how to add swiping feature

  • By default android collection view’s are recycled for better performance. This includes GridView, ListView, RecyclerView, etc. Only view’s that are currently shown are held in memory others get freed to make more space for app to run comfortably. So that is a standard behavior and recommended if you have more grid items.

    You may have to work with making the view to load faster when scrolled, instead of removing the recycling feature. Look into a better image caching library, I recommend Volley, Picasso, or Universal image loader. Also use view holder design pattern for smooth scrolling.

  • Ummi Azahar

    Hello, can you send me your php file for this tutorial ? Thank you

    • This is a native Android code. What is php file to do with this?

      • Ummi Azahar

        I’m sorry because i’m a beginner to android. Perhaps, can you explain me how to fetch an images into gridview from the folder stored in the server ? And what is the “posts”, “attachment” and “url” stand for to fetch the image ? Thank you for helping

  • Patient Baïse

    cache load offline is not available

  • sunder

    Does this work with google spreadsheet ??If we take input from spreadsheet online …any idea ??please can u help me with the code

  • Vikhyath Maiya

    great tutorial…can u please post d server side codes for this???

  • Vikhyath Maiya

    great tutorial…can u please post d server side codes for this???

  • MK

    Where is the GridItem class? You mention that you’re going to make it, but there’s no code for it.

    EDIT: oh, found it in your Github.