分享

Android Custom ListView with Image and Text using Volley

 quasiceo 2014-11-01

My previous article Customized ListView with Image and Text gives you a good overview of customizing a list view which contains a thumbnail image and few text fields. All the list data will be downloaded by making a network calls. The main challange in that tutorial is downloading the images asynchronously and caching them. Because of lack of good tools I used a third party library (it is a good library though) to download the listview data and caching the images.

Today I am going to explain the same, but this time with a different approach by using an another library called volley. By using volley you can see decent improvement in listview performance without much effort.

DOWNLOAD CODE

Final Output

The list view we are going to build contains list of movies information where each list row defines single movie. The row layout is customized that contains movie poster as thumbnail image on the left and the movie title, rating, genre and release date on the right. Below is the final output.

android custom listview with image and text using volley

1. Example JSON

I am going to use thisexample jsonto load the list data. This json contains array of objects where the each object contains information like movie name, rating, genre and release date.

JSON Url: http://api./json/movies.json

[
  {
    "title": "Dawn of the Planet of the Apes",
    "image": "http://api./json/movies/1.jpg",
    "rating": 8.3,
    "releaseYear": 2014,
    "genre": ["Action", "Drama", "Sci-Fi"]
  },
  ....
  ....
]

2. Downloading Volley Library (volley.jar)

If you are coming across volley for the first time, I would suggest you go through my previous article Android working with Volley Library which gives you enough knowledge about volley and other things like building the volley library to generate volley.jar. It is up to you that you want to generate volley.jar on your own or just download the thevolley.jar

3. Planning The Layout Design

To achieve this customized layout I choose the RelativeLayout as parent element. All the child elements are aligned using relative properties like align below, align right, align parent bottom etc.,

android custom list view design

Now let’s start by creating a new project.

4. Creating New Project

1 . In Eclipse create a new project by navigating to File ? New ? Android Application Project and fill required details. I gave my project package name as

info.androidhive.customlistviewvolley

2 . Once the project is created paste the volley.jar in libs folder.

3 . I am creating required packages first just to keep the project organized. This step is optional but it is recommended. Create four packages named adapter , app , model and util . So after creating packages my project contains following.

info.androidhive.customlistviewvolley.adater

info.androidhive.customlistviewvolley.app

info.androidhive.customlistviewvolley.model

info.androidhive.customlistviewvolley.util

4 . Open colors.xml under res ? values and add below colors. If you don’t see colors.xml file, create a new file and add these color values.

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

  <color name="genre">#666666</color>
  <color name="year">#888888</color>
  <color name="list_divider">#d9d9d9</color>
  <color name="list_row_start_color">#ffffff</color>
  <color name="list_row_end_color">#ffffff</color>
  <color name="list_row_hover_start_color">#ebeef0</color>
  <color name="list_row_hover_end_color">#ebeef0</color>

</resources>

5 . Also add below dimensions in dimens.xml file located under res ? values .

<resources>
    
  <dimen name="title">17dp</dimen>
  <dimen name="rating">15dip</dimen>
  <dimen name="genre">13dip</dimen>
  <dimen name="year">12dip</dimen>

</resources>

6 . Before start writing java code, I would like to complete the UI part first. Create list_row_bg.xml , list_row_bg_hover.xml and list_row_selector.xml with below respective codes under res ? drawable folder. If you don’t see drawable folder under res, create a new folder and name it as drawable.

list_row_bg.xml – Default style for list view row.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas./apk/res/android"
    android:shape="rectangle">
  <gradient
      android:startColor="@color/list_row_start_color"
      android:endColor="@color/list_row_end_color"
      android:angle="270" />
</shape>

list_row_bg_hover.xml – Style for list view row when row is selected

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

  <gradient
    android:angle="270"
    android:endColor="@color/list_row_hover_end_color"
    android:startColor="@color/list_row_hover_start_color" />

</shape>

list_row_selector.xml – Selector file to toggle the row states.

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

    <item android:drawable="@drawable/list_row_bg" android:state_pressed="false" android:state_selected="false"/>
    <item android:drawable="@drawable/list_row_bg_hover" android:state_pressed="true"/>
    <item android:drawable="@drawable/list_row_bg_hover" android:state_pressed="false" android:state_selected="true"/>

</selector>

7 . Now open your layout file of main activity(in my case activity_main.xml ) and add a ListView element.

<RelativeLayout xmlns:android="http://schemas./apk/res/android"
  xmlns:tools="http://schemas./tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity" >

  <ListView
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:divider="@color/list_divider"
    android:dividerHeight="1dp"
    android:listSelector="@drawable/list_row_selector" />

</RelativeLayout>

8 . We need to create another layout file for list view row. This is the main design component in this project as we define actual custom list design here. I am naming this file as list_row.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas./apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:background="@drawable/list_row_selector"
  android:padding="8dp" >

  <!-- Thumbnail Image -->
  <com.android.volley.toolbox.NetworkImageView
    android:id="@+id/thumbnail"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:layout_alignParentLeft="true"
    android:layout_marginRight="8dp" />

  <!-- Movie Title -->
  <TextView
    android:id="@+id/title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignTop="@+id/thumbnail"
    android:layout_toRightOf="@+id/thumbnail"
    android:textSize="@dimen/title"
    android:textStyle="bold" />

  <!-- Rating -->
  <TextView
    android:id="@+id/rating"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/title"
    android:layout_marginTop="1dip"
    android:layout_toRightOf="@+id/thumbnail"
    android:textSize="@dimen/rating" />
  
  <!-- Genre -->
  <TextView
    android:id="@+id/genre"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/rating"
    android:layout_marginTop="5dp"
    android:layout_toRightOf="@+id/thumbnail"
    android:textColor="@color/genre"
    android:textSize="@dimen/genre" />

  <!-- Release Year -->
  <TextView
    android:id="@+id/releaseYear"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:textColor="@color/year"
    android:textSize="@dimen/year" />

</RelativeLayout>

Here we completed the design part. Let’s move to java part.

9 . Create LruBitmapCache.java under util package. This class takes care of caching images on disk.

package info.androidhive.customlistviewvolley.util;

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

10 . Create AppController.java under app package. This class is a singleton class which initializes core objects of volley library.

package info.androidhive.customlistviewvolley.app;

import info.androidhive.customlistviewvolley.util.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;

  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) {
      mImageLoader = new ImageLoader(this.mRequestQueue,
          new LruBitmapCache());
    }
    return this.mImageLoader;
  }

  public <T> void addToRequestQueue(Request<T> req, String tag) {
    // set the default tag if tag is empty
    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);
    }
  }
}

11 . Now add the AppController.java class in AndroidManifest.xml to your <application> tag using name property to execute this class on application start. Also add INTERNET permission as we are going to make network calls.

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

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

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

  <application
    android:name="info.androidhive.customlistviewvolley.app.AppController"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
      android:name="info.androidhive.customlistviewvolley.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>

12 . Now create Movie.java under model package. This model class will be used to provide movie objects data to list view after parsing the json.

package info.androidhive.customlistviewvolley.model;

import java.util.ArrayList;

public class Movie {
  private String title, thumbnailUrl;
  private int year;
  private double rating;
  private ArrayList<String> genre;

  public Movie() {
  }

  public Movie(String name, String thumbnailUrl, int year, double rating,
      ArrayList<String> genre) {
    this.title = name;
    this.thumbnailUrl = thumbnailUrl;
    this.year = year;
    this.rating = rating;
    this.genre = genre;
  }

  public String getTitle() {
    return title;
  }

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

  public String getThumbnailUrl() {

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多