Android JSON - GridView CardViews Images Text - Download,Parse,Show


How to populate custom gridview with json data containing images and text.

In this tutorial we want to se how to download some JSON data from online asynchronously, parse that data and bind to a custom gridview with cardviews.

We are fetching images and text in our gridview. So our custom gridview will have cardviews that render for us images and text in a nice way.

We will be using the Fast Networking library which is built on top OkHttp. This will provide us with a fast and easy to work networking capability.

We are making a HTTP GET request. As our data is downloaded, we will show an indeterminate progressbar will be hidden automatically when the data download is finish.

This allows us to show user the download progress. In case of any error, we will show a Toast message containing details about the error so that you can view it at runtime, which is very important for newbies.

Let's start.

What You Learn

  1. Handling JSON data containing images and text in android.
  2. Using Fast Networking Library with JSON and GridView.
  3. How to create custom gridview with cardviews containing images and text.
  4. Loading JSON data asynchronousl with progress bar.

Project structure

Android JSON GridView Images and Text

Build.gradle

Given we will be using Fast Android Networking Library, we have to add its dependency.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.12'
    implementation 'com.android.support:appcompat-v7:26.+'
    implementation 'com.android.support:cardview-v7:26.+'
    implementation 'com.android.support:design:26.+'
    implementation 'com.amitshekhar.android:android-networking:1.0.1'
    implementation 'com.squareup.picasso:picasso:2.71828'
}

AndroidManifest.xml

We will be fetching our json data from online so we have to add internet permission in our android manifest.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.camposha.jsoncardviewsgridview">
...
    <uses-permission android:name="android.permission.INTERNET"/>
....
</manifest>
(b). build.gradle(project)

This is our project level build.gradle file. It's sometimes called root level build.gradle file since it's located at the project's root folder.

Most of the time we modify this file if we want to register another repository where probably one of our dependencies will be downloaded.

We normally register under the allProject's DSL.

Resources.

Android platform provides a powerful and flexible way of adding static content as a resource.

These static content will also be packaged into the APK file. The static content will be stored either as a resource or as an asset.

Resources belong to a given type. These types can be:

  1. Drawable.
  2. Layout.
  3. Value.

Let's start by looking at the layout resources

(a). activity_main.xml

This layout will get inflated into the main activity's user interface. This will happen via the Activity's setContentView() method which will require us to pass it the layout.

We will do so inside the onCreate() method of Activity.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="info.camposha.jsoncardviewsgridview.MainActivity">
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Spacecrafts App"
        android:textAlignment="center"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        android:textColor="@color/colorAccent" />

    <ProgressBar
        android:id="@+id/myProgressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:indeterminate="true"
        android:indeterminateBehavior="cycle"
        android:visibility="gone" />

    <GridView
        android:id="@+id/myGridView"
        android:layout_weight="0.5"
        android:numColumns="auto_fit" 
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/downloadBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        android:text="Download" />
</LinearLayout>
(b). row_model.xml

This will define our custom cardview which will be our grid item for our GridView.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="10dp"
    android:layout_height="300dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            android:padding="10dp"
            android:src="@drawable/placeholder"
             />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text="Quote"
                android:id="@+id/quoteTxt"
                android:padding="5dp"
                android:layout_below="@+id/imageView"
                android:layout_alignParentLeft="true"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text=" Author --------------------"
                android:id="@+id/authorTxt"
                android:textColor="@color/colorAccent"
                android:padding="5dp"
                android:layout_below="@+id/quoteTxt"
                android:layout_alignParentLeft="true"
                />

        <CheckBox
            android:id="@+id/chkTechExists"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="13dp"
            android:layout_marginEnd="13dp"
            android:layout_marginRight="13dp"
            android:checked="true"
            android:text="Technology Exists?" />

    </RelativeLayout>

</android.support.v7.widget.CardView>

Java Code.

Android apps can be mainly written in Java or Kotlin. These days however there are many frameworks like Flutter also which use languages like Dart.

In this class we are using Java programming language.

We will have these classes in our project.

(a). MainActivity.java

This is our launcher activity as the name suggests. This means it will be the main entry point to our app in that when the user clicks the icon for our app, this activity will get rendered first.

We override a method called onCreate(). Here we will start by inflating our main layout via the setContentView() method.

Our main activity is actually an activity since it's deriving from the AppCompatActivity.

package info.camposha.jsoncardviewsgridview;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.androidnetworking.AndroidNetworking;
import com.androidnetworking.common.Priority;
import com.androidnetworking.error.ANError;
import com.androidnetworking.interfaces.JSONArrayRequestListener;
import com.squareup.picasso.Picasso;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    /*
    Our data object
     */
    public class Spacecraft {
        /*
        INSTANCE FIELDS
         */
        private int id;
        private String name;
        private String propellant;
        private String imageURL;
        private int technologyExists;
        /*
        GETTERS AND SETTERS
         */
        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 getPropellant() {
            return propellant;
        }
        public void setEmail(String propellant) {
            this.propellant = propellant;
        }
        public String getImageURL() {
            return imageURL;
        }
        public void setImageURL(String imageURL) {
            this.imageURL = imageURL;
        }
        public int getTechnologyExists() {
            return technologyExists;
        }
        public void setTechnologyExists(int technologyExists) {
            this.technologyExists = technologyExists;
        }
        /*
        TOSTRING
         */
        @Override
        public String toString() {
            return name;
        }
    }
    /*
    Our custom adapter class
     */
    public class GridViewAdapter extends BaseAdapter {

        Context c;
        ArrayList<Spacecraft> spacecrafts;

        public GridViewAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
            this.c = c;
            this.spacecrafts = spacecrafts;
        }
        @Override
        public int getCount() {
            return spacecrafts.size();
        }
        @Override
        public Object getItem(int i) {
            return spacecrafts.get(i);
        }
        @Override
        public long getItemId(int i) {
            return i;
        }
        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            if(view==null)
            {
                view= LayoutInflater.from(c).inflate(R.layout.row_model,viewGroup,false);
            }

            TextView txtName = view.findViewById(R.id.quoteTxt);
            TextView txtPropellant = view.findViewById(R.id.authorTxt);
            CheckBox chkTechExists = view.findViewById(R.id.chkTechExists);
            ImageView spacecraftImageView = view.findViewById(R.id.imageView);

            final Spacecraft s= (Spacecraft) this.getItem(i);

            txtName.setText(s.getName());
            txtPropellant.setText(s.getPropellant());
            chkTechExists.setEnabled(true);
            chkTechExists.setChecked( s.getTechnologyExists()==1);
            chkTechExists.setEnabled(false);

            if(s.getImageURL() != null && s.getImageURL().length()>0)
            {
                Picasso.get().load(s.getImageURL()).placeholder(R.drawable.placeholder).into(spacecraftImageView);
            }else {
                Toast.makeText(c, "Empty Image URL", Toast.LENGTH_LONG).show();
                Picasso.get().load(R.drawable.placeholder).into(spacecraftImageView);
            }
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(c, s.getName(), Toast.LENGTH_SHORT).show();
                }
            });

            return view;
        }
    }

    /*
    Our HTTP Client
     */
    public class JSONDownloader {

        //SAVE/RETRIEVE URLS
        private static final String JSON_DATA_URL="https://cdn.rawgit.com/Oclemy/SampleJSON/338d9585/spacecrafts.json";
        //INSTANCE FIELDS
        private final Context c;
        private GridViewAdapter adapter ;

        public JSONDownloader(Context c) {
            this.c = c;
        }
        /*
        RETRIEVE/SELECT/REFRESH
         */
        public void retrieve(final GridView gv, final ProgressBar myProgressBar)
        {
            final ArrayList<Spacecraft> spacecrafts = new ArrayList<>();

            myProgressBar.setIndeterminate(true);
            myProgressBar.setVisibility(View.VISIBLE);

            AndroidNetworking.get(JSON_DATA_URL)
                    .setPriority(Priority.HIGH)
                    .build()
                    .getAsJSONArray(new JSONArrayRequestListener() {
                        @Override
                        public void onResponse(JSONArray response) {
                            JSONObject jo;
                            Spacecraft s;
                            try
                            {
                                for(int i=0;i<response.length();i++)
                                {
                                    jo=response.getJSONObject(i);

                                    int id=jo.getInt("id");
                                    String name=jo.getString("name");
                                    String propellant=jo.getString("propellant");
                                    String techExists=jo.getString("technologyexists");
                                    String imageURL=jo.getString("imageurl");

                                    s=new Spacecraft();
                                    s.setId(id);
                                    s.setName(name);
                                    s.setEmail(propellant);
                                    s.setImageURL(imageURL);
                                    s.setTechnologyExists(techExists.equalsIgnoreCase("1") ? 1 : 0);

                                    spacecrafts.add(s);
                                }

                                //SET TO SPINNER
                                adapter =new GridViewAdapter(c,spacecrafts);
                                gv.setAdapter(adapter);
                                myProgressBar.setVisibility(View.GONE);

                            }catch (JSONException e)
                            {
                                myProgressBar.setVisibility(View.GONE);
                                Toast.makeText(c, "GOOD RESPONSE BUT JAVA CAN'T PARSE JSON IT RECEIEVED. "+e.getMessage(), Toast.LENGTH_LONG).show();
                            }
                        }
                        //ERROR
                        @Override
                        public void onError(ANError anError) {
                            anError.printStackTrace();
                            myProgressBar.setVisibility(View.GONE);
                            Toast.makeText(c, "UNSUCCESSFUL :  ERROR IS : "+anError.getMessage(), Toast.LENGTH_LONG).show();
                        }
                    });
        }
    }

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

        final GridView myGridView= findViewById(R.id.myGridView);
        Button btnRetrieve= findViewById(R.id.downloadBtn);
        final ProgressBar myProgressBar= findViewById(R.id.myProgressBar);

        //EVENTS : RETRIEVE
        btnRetrieve.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new JSONDownloader(MainActivity.this).retrieve(myGridView,myProgressBar);

            }
        });
    }
}

How do You Feel after reading this?

According to scientists, we humans have 8 primary innate emotions: joy, acceptance, fear, surprise, sadness, disgust, anger, and anticipation. Feel free to tell us how you feel about this article using these emotes or via the comment section. This feedback helps us gauge our progress.

Help me Grow.

I set myself some growth ambitions I desire to achieve by this year's end regarding this website and my youtube channel. Am halfway. Help me reach them by:




Recommendations


What do You Think


Previous Post Next Post