Android PHP MySQL - Images and Text - Select then Fill ListView


Android PHP MySQL - Images and Text - Select then Fill ListView*

Android MySQL images text listview Tutorial. We see how to select images and text from mysql databse and show in a ListView.

Part 1 - Introduction

Applications are many that show lists of data in google play.Most of the time these images aren't stored locally.That would be a disaster in terms of the amount of storage these applications utilize as well as the overall performance of the application.

These images usually have to be in some ways dynamic.Image manipulations when done locally can be quite resource intensive,hence the resizing and manipulations can be done in the server side.Anyway today we want to see how to retrieve images from a  MySQL database and show them in our ListView.

We only retrieve the image urls from the database and render the images using Picasso.This ensures we can lazily load the images and can even resize them without any considerable performance penalty.We show text alongside the images.  

What we do :
  • Fetch images urls and text from MySQL database.
  • Of course via PHP.
  • We make a HTTP GET Request hence receiving a blob of json data.
  • This data,the json array,we parse it using JSONArray and JSONObject classes in our java android.
  • We render the images using Picasso ImageLoader library.
  • The ListView consists of images and text.
  • We are using AsyncTask to perform this GET request.
  • This ensures our Main Thread remains responsive.
  • To show user progress we use ProgressDialog.
  • Both parsing and downloading data,we abstract them in separate classes.
  • We also do both in background thread.
Common Questions we answer :
  • Images and Text MySQL database.
  • Image URLs MySQL database.
  • Android MySQL Select data.
  • Fill ListView From MySQL.
  • Custom ListView with Images and Text.
  • AsyncTask threading.
  • PHP MySQL android select data.
  • Download JSON AsyncTask.
  • parse JSON AsyncTask.
  • Show progress asynctask.
  • Making HTTP GET Request.
  • Picasso Imageloader to load images to ListView.
What You'll do :
  • Create a project in android studio.
  • Give it a name and choose minimum and target SDKs.
  • Add permission for internet connection in your android manifest.
  • Add a dependency statement for a Picasso library we'll use.
  • Create a MySQL table and write some PHP code.
  • Run your project.
  • I tested mine in bluestacks emulator.
Overview :

Classes

  1. MainActivity class
  2. Spacecraft class
  3. Connector class.
  4. Downloader class.
  5. DataParser class.
  6. CustomAdapter class

Layouts

  1. ActivityMain.xml
  2. ContentMain.xml
  3. Model.xml

AndroidManifest.xml

  1. Add Permission for Internet

Project Structure

Project Structure Image

Expected results

Android MySQL ListView](http://camposha.info) Android MySQL ListView[/caption]

Part 2 - PHP Script

Below is our PHP script we used in this tutorial.You need to use your own database credentials.

  • The script selects data from mysql database.
  • It then encodes it into JSON format.
  • When we make a GET request we end up with the JSON array.
<?php

$host='127.0.0.1';
$username='root';
$pwd='';
$db="spacecraftDB";

$con=mysqli_connect($host,$username,$pwd,$db) or die('Unable to connect');

if(mysqli_connect_error($con))
{
  echo "Failed to Connect to Database ".mysqli_connect_error();
}
$sql="SELECT * FROM spacecraftTB";
$result=mysqli_query($con,$sql);

if($result)
{
  while($row=mysqli_fetch_array($result))
  {
    $data[]=$row;
  }
  print(json_encode($data));
}
mysqli_close($con);
?>

Test your script on the browser after creating database and adding data.If right you should see JSON like below :

JSON

Part 3 - Layouts

We chose Basic activity so two layouts are auto created by android studio.ActivityMain.xml and ContentMain.xml. We then go ahead and create Model.xml.  

Android MySQL ListView

(a). activity_main.xml
  • Inflated as our activity’s view.
  • Includes our content main layout.
  • Contains support.v4 widgets like Cordinatorlayout, appbarlayout, toolbar and our floating action button view.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.mysqllistviewimages.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
(b). ContentMain.xml Layout.
  • Lets add our ListView here.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.mysqllistviewimages.MainActivity"
    tools:showIn="@layout/activity_main">

    <ListView
        android:id="@+id/lv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />
</RelativeLayout>
(c). Model.xml Layout.
  • This shall get inflated to a single view item in our ListView.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_margin="10dp"
    card_view:cardCornerRadius="5dp"
    card_view:cardElevation="5dp"
    android:layout_height="150dp">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ImageView
            android:layout_width="250dp"
            android:layout_height="wrap_content"
            android:id="@+id/movieImage"
            android:padding="10dp"
            android:src="@drawable/fruits" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Name"
            android:id="@+id/nameTxt"
            android:padding="10dp"
            android:textColor="@color/colorAccent"
            android:layout_alignParentLeft="true"
             />

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

Part 3 - Java Code

In this part we are going to write some java code.We prefer to break down our work into one class one responsibility so we may use many classes.  

Classes

(a). Build.Gradle

  • We are using Picasso library to load our images,so we need its dependency.
  • We are using CardViews within our custom ListView.
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'
    //compile project(':picasso-2.5.2')
     compile 'com.squareup.picasso:picasso:2.5.2'

}

   

(b). AndroidManifest.xml
  • Add Internet permission cause we are downloading the images via their urls from our mysql database via php code.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tutorials.hp.mysqllistviewimages">

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

</manifest>

   

(c). Spacecraft.java
  • Represents a singe data object.
package com.tutorials.hp.mysqllistviewimages.m_DataObject;

public class Spacecraft {

    int id;
    String name;
    String imageUrl;

    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 getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}

   

(d). Connector Class
  • Responsible for connection to network.
  • We use HTTPUrlConnetion.
  • We are making a HTTP GET request to server,
package com.tutorials.hp.mysqllistviewimages.m_MySQL;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

public class Connector {

    public static HttpURLConnection connect(String urlAddress)
    {
        try {
            URL url=new URL(urlAddress);
            HttpURLConnection con= (HttpURLConnection) url.openConnection();

            //CON PROP
            con.setRequestMethod("GET");
            con.setConnectTimeout(20000);
            con.setReadTimeout(20000);
            con.setDoInput(true);

            return con;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}

   

(e). Data Downloader Class
  • Downloads data in the background thread via asynctask.
  • Meanwhile we show a progress dialog
  • The data is then parsed to Data parser class to be parsed.
package com.tutorials.hp.mysqllistviewimages.m_MySQL;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.ListView;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;

public class Downloader extends AsyncTask<Void,Void,String> {

    Context c;
    String urlAddress;
    ListView lv;

    ProgressDialog pd;

    public Downloader(Context c, String urlAddress, ListView lv) {
        this.c = c;
        this.urlAddress = urlAddress;
        this.lv = lv;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        pd=new ProgressDialog(c);
        pd.setTitle("Retrieve");
        pd.setMessage("Retrieving...Please wait");
        pd.show();
    }

    @Override
    protected String doInBackground(Void... params) {
        return downloadData();
    }

    @Override
    protected void onPostExecute(String jsonData) {
    super.onPostExecute(jsonData);

        pd.dismiss();

        if(jsonData==null)
        {
            Toast.makeText(c,"Unsuccessful,No data Retrieved",Toast.LENGTH_SHORT).show();
        }else {
            //PARSE
            DataParser parser=new DataParser(c,jsonData,lv);
            parser.execute();

        }
    }

    private String downloadData()
    {
        HttpURLConnection con=Connector.connect(urlAddress);
        if(con==null)
        {
            return null;
        }

        try
        {
            InputStream is=new BufferedInputStream(con.getInputStream());
            BufferedReader br=new BufferedReader(new InputStreamReader(is));

            String line;
            StringBuffer jsonData=new StringBuffer();

            while ((line=br.readLine()) != null)
            {
                jsonData.append(line+"n");
            }

            br.close();
            is.close();

            return jsonData.toString();

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }
}

   

(f). Data Parser Class
  • Parses our downloaded json data natively.
  • Then passes this data to CustomAdapter to be bound.
package com.tutorials.hp.mysqllistviewimages.m_MySQL;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.ListView;
import android.widget.Toast;

import com.tutorials.hp.mysqllistviewimages.m_DataObject.Spacecraft;
import com.tutorials.hp.mysqllistviewimages.m_UI.CustomAdapter;

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

import java.util.ArrayList;

public class DataParser extends AsyncTask<Void,Void,Integer> {

    Context c;
    String jsonData;
    ListView lv;

    ProgressDialog pd;
    ArrayList<Spacecraft> spacecrafts=new ArrayList<>();

    public DataParser(Context c, String jsonData, ListView lv) {
        this.c = c;
        this.jsonData = jsonData;
        this.lv = lv;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        pd=new ProgressDialog(c);
        pd.setTitle("Parse");
        pd.setMessage("Parsing...Please wait");
        pd.show();
    }

    @Override
    protected Integer doInBackground(Void... params) {
        return this.parseData();
    }

    @Override
    protected void onPostExecute(Integer result) {
        super.onPostExecute(result);

        pd.dismiss();

        if(result==0)
        {
            Toast.makeText(c,"Unable To Parse",Toast.LENGTH_SHORT).show();
        }else {
            //BIND DATA TO LISTVIEW
            CustomAdapter adapter=new CustomAdapter(c,spacecrafts);
            lv.setAdapter(adapter);
        }
    }

    private int parseData()
    {
        try
        {
            JSONArray ja=new JSONArray(jsonData);
            JSONObject jo=null;

            spacecrafts.clear();
            Spacecraft spacecraft;

            for(int i=0;i<ja.length();i++)
            {
                jo=ja.getJSONObject(i);

                int id=jo.getInt("id");
                String name=jo.getString("name");
                String imageUrl=jo.getString("imageurl");

                spacecraft=new Spacecraft();

                spacecraft.setId(id);
                spacecraft.setName(name);
                spacecraft.setImageUrl(imageUrl);

                spacecrafts.add(spacecraft);
            }

            return 1;

        } catch (JSONException e) {
            e.printStackTrace();
        }

        return 0;
    }
}

 

(g). Picasso Client class
  • Uses Picasso ImageLoader to download our image into an imageview.
package com.tutorials.hp.mysqllistviewimages.m_UI;

import android.content.Context;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;
import com.tutorials.hp.mysqllistviewimages.R;

public class PicassoClient {

    public static void downloadImage(Context c,String imageUrl,ImageView img)
    {
        if(imageUrl.length()>0 && imageUrl!=null)
        {
            Picasso.with(c).load(imageUrl).placeholder(R.drawable.placeholder).into(img);
        }else {
            Picasso.with(c).load(R.drawable.placeholder).into(img);
        }
    }

}

   

(h). Custom Adapter class
  • Subclasses BaseAdapter.
  • Inflates our custom layout.
  • Binds our data into our adapterview.
package com.tutorials.hp.mysqllistviewimages.m_UI;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.tutorials.hp.mysqllistviewimages.R;
import com.tutorials.hp.mysqllistviewimages.m_DataObject.Spacecraft;

import java.util.ArrayList;

public class CustomAdapter extends BaseAdapter {

    Context c;
    ArrayList<Spacecraft> spacecrafts;

    LayoutInflater inflater;

    public CustomAdapter(Context c, ArrayList<Spacecraft> spacecrafts) {
        this.c = c;
        this.spacecrafts = spacecrafts;

        inflater= (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

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

    @Override
    public Object getItem(int position) {
        return spacecrafts.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
   @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView==null)
        {
            convertView=inflater.inflate(R.layout.model,parent,false);
        }

        TextView nametxt= (TextView) convertView.findViewById(R.id.nameTxt);
        ImageView img= (ImageView) convertView.findViewById(R.id.movieImage);

        //BIND DATA
        Spacecraft spacecraft=spacecrafts.get(position);

        nametxt.setText(spacecraft.getName());

        //IMG
        PicassoClient.downloadImage(c,spacecraft.getImageUrl(),img);

        return convertView;
    }
}

 

(i). MainActivity
  • Launcher activity.
  • Executes our Downloader Asynctask class to start downloading on floating action button click.
package com.tutorials.hp.mysqllistviewimages;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.ListView;

import com.tutorials.hp.mysqllistviewimages.m_MySQL.Downloader;

public class MainActivity extends AppCompatActivity {

    final static String urlAddress="http://10.0.2.2/android/spacecraft_select_images.php";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        final ListView lv= (ListView) findViewById(R.id.lv);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Downloader(MainActivity.this,urlAddress,lv).execute();
            }
        });
    }

}

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