Q:

ListView: Populate listview with images from JSON

I have a listview which works perfectly when it comes to displaying all the text from a database through Php/JSON.  However, in the database there is an image link associated with every item which I would like to show in the listview.  Basically what it does is that a person clicks the search button and the default android search bar in action menu appears where they enter the word.  Then it goes to the server and sends the word and tries to find all the matches from the database and pulls it.  Now it works perfectly with displaying the textviews but for some reason I am unable to display images.  Can someone show me how do it?  I tried few times but I failed so hence the code I am providing you is my up to date code:
public class ListResult extends ListActivity {

    // Progress Dialog
    private ProgressDialog pDialog;

    // Creating JSON Parser object
    JSONParser jParser = new JSONParser();

    ArrayList<HashMap<String, String>> UserBooksList;

    // url to get the idiom list
    private static String url_search =   
    "http://randomurl.com/arandomapp/search.php";

    // JSON Node names
    private static final String TAG_SUCCESS = "success";
    private static final String TAG_UserBooks = "UserBooks";
    private static final String TAG_BName = "BName";
    private static final String TAG_NAME = "name";

    // THIS TAG BELOW IS THE ONE WHICH SHOWS THE IMAGE URL. 
    private static final String TAG_IMG = "Id";

    // products JSONArray
    JSONArray user_books = null;

    // The keyword send to server and displays the result. 
    public String search_key;

    TextView mError;

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

    // get the action bar
    ActionBar actionBar = getActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

    if (savedInstanceState == null) {
        Bundle extras = getIntent().getExtras();
        if(extras == null) {
            search_key = null;
        } else {
            search_key = extras.getString("keyword");
        }
    } else {
        search_key = (String) savedInstanceState.getSerializable("keyword");
    }

    UserBooksList = new ArrayList<>();

    // Loading idioms in Background Thread
    new LoadIdioms().execute();

    mError = (TextView) findViewById(R.id.error);
    mError.setVisibility(View. GONE);

    actionBar.setTitle("Relevant Searches For: " + search_key);
    actionBar.setIcon(R.drawable.ic_action_search);
}

class LoadIdioms extends AsyncTask<String, String, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(ListResult.this);
        pDialog.setMessage("Loading Data.  Please wait...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    protected String doInBackground(String... args) {

        // Building Parameters
        List<NameValuePair> params = new ArrayList<>();

        //value captured from previous intent
        params.add(new BasicNameValuePair("keyword", search_key));

        // getting JSON string from URL
        JSONObject json = jParser.makeHttpRequest(url_search, "GET",    
params);

        try {

            int success = json.getInt(TAG_SUCCESS);

            if (success == 1) {

                user_books = json.getJSONArray(TAG_UserBooks);

                for (int i = 0; i < user_books.length(); i++) {
                    JSONObject c = user_books.getJSONObject(i);

                    // Storing each json item in variable
                    String bName = c.getString(TAG_BName);
                    String Name = c.getString(TAG_NAME);
                    String b_img = c.getString(TAG_IMG);

                    // creating new HashMap
                    HashMap<String, String> map = new HashMap<>();

                    // adding each child node to HashMap key => value
                    map.put(TAG_BName, bName);
                    map.put(Tag_NAME, Name);
                    map.put(TAG_IMG, b_img);

                    // adding HashList to ArrayList
                    UserBooksList.add(map);

                }
            } else {
                Log.d("Login Failure!",  json.getString(TAG_MESSAGE));
                return json.getString(TAG_MESSAGE);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }

    protected void onPostExecute(String file_url) {

        // dismiss the dialog after getting the related idioms
        pDialog.dismiss();

        // updating UI from Background Thread
        runOnUiThread(new Runnable() {

            public void run() {
                /**
                 * Updating parsed JSON data into ListView
                 **/

                ListAdapter adapter = new SimpleAdapter(
                        ListResult.this, UserBooksList,
                        R.layout.list_item, new String[] {TAG_BName, TAG_Name},
                        new int[] {R.id. BName, R.id. Name});

                // updating listview
                setListAdapter(adapter);
            }
        });

        // dismiss the dialog once product deleted
        pDialog.dismiss();
        if (file_url ! = null){
            mError = (TextView) findViewById(R.id.error);
            mError.setVisibility(View. VISIBLE);
            mError.setText("Sorry, No Books were found.  Please try again."); 
        }
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.activity_main_actions_two, menu);

    return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Take appropriate action for each action item click
    switch (item.getItemId()) {
        case R.id.action_help:
            // help action
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
}

Can anyone suggest to me how I would incorporate the idea of also setting the images while its loading?  I mean the url's of the images are being fetched perfectly when I tried it.  
I have a list_item.xml which contains the textview for the name and an imageView which has an id: ImageView3. 
THANKS :) 

A:

Its good practice to work with objects in Java thus first create a new class named UserBook with the following code :
public class UserBook {

private String name;
private String BName;
private String imageUrl;

public UserBook() {
}

public String getName() {
    return name;
}

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

public String getBName() {
    return BName;
}

public void setBName(String BName) {
    this. BName = BName;
}

public String getImageUrl() {
    return imageUrl;
}

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

Now the ArrayList in your list activity you initiate it like so :
private ArrayList<UserBook> userBooksList;

To fill our arraylist is easy, just create a new UserBook object and put it into our array :
    UserBook book = new UserBook();

    book.setName(Name);
    book.setBName(bName);
    book.getImageUrl(b_img);

    userBookList.add(book);

Create a new XML layout file and name it cell.  this will be our custom cell our adapter will use to display data in the listview. 
<? xml version="1.0" encoding="utf-8"? >

<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/cell_imageView" />

<LinearLayout
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Medium Text"
        android:id="@+id/cell_textView" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:id="@+id/cell_textView2" />
</LinearLayout>

So here it comes the most important part, our custom adapter for our listview.  Create a new class name it MyCustomAdapter :
public class MyCustomAdapter extends ArrayAdapter<UserBook> {

Context context;

public MyCustomAdapter(Context context, int resource, ArrayList<UserBook> books) {
    super(context, resource, books);

  //UPDATE!!!! 
  this.context = context;

}

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

    Holder holder;

    //First we check if the cell is being created for the first time, if its the case we inflate from
    //our xml

    if (cell == null){

        holder = new Holder();

        //get the xml inflator service
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context. LAYOUT_INFLATER_SERVICE);

        //Fill our cell with the xml
        cell = inflater.inflate(R.layout.cell, null);

        //Fill our holder with components
        holder.imageView = (ImageView)cell.findViewById(R.id.cell_imageView);
        holder.textView = (TextView)cell.findViewById(R.id.cell_textView);
        holder.textView2 = (TextView)cell.findViewById(R.id.cell_textView2);

        //this is very important..here we are attaching the holder to the current row
        cell.setTag(holder);
    }else{

        //the cell was created before so we can grab the holder attached
        holder = (Holder)cell.getTag();
    }

    //get current book item
    UserBook book = getItem(position);

    //fill data
    holder.textView.setText(book.getName());
    holder.textView2.setText(book.getBName());

    //set picasso
    Picasso.with(context).load(Uri.parse(book.getImageUrl())).into(holder.imageView);

    return cell;
}

//The holder will hold the inflated views and attach them to the listview's row
//for performance
private class Holder{

    ImageView imageView;
    TextView textView;
    TextView textView2;

}

}

To use our custom adapter simply :
 MyCustomAdapter adapter = new MyCustomAdapter(context, R.layout.cell, userBookList);

    listView.setAdapter(adapter);

Please study this , im available for help, since this is the best practise in Android to handle listviews

