Android Custom ListView with Image and Text

    Rating: ★★★★☆
    View: 211
    Download: 90
    Từ khóa:

    In this tutorial I explained how to load images from remote url and update into listview. Also explained how to design listview with your custom styles and colors instead of using default listview style.

    The Sample XML

    For this tutorial I am using following sample XML which has some data and a thumbnail image url. You can get this XML by accessing http:/isource.vn/upload/music.xml

    
    
        
            1
            Someone Like You
            Adele
            4:47
            1662
            http://api.androidhive.info/music/images/adele.png
        
        
            2
            Space Bound
            Eminem
            4:38
            1900
            http://api.androidhive.info/music/images/eminem.png
        
           .
           .
           .
           .
    

    Creating New Project

    1. Create new project in your Eclipse IDE and fill all the details. File ⇒ New Project
    2. If you notice the screen shots I designed listview with gradient background. To define gradient style create three new XML files under drawable folder and name them as gradient_bg.xml,list_selector.xml and gradient_bg_hover.xml and fill with following code. Also the thumbnail image has white background, for this I used image_bg.xml
    Right Click and drawable-hdpi ⇒ New ⇒ Android XML File

    gradient_bg.xml – Default Background Gradient Style

    gradient_bg.xml
    
    
      
    
    gradient_bg_hover.xml – Gradient Style for on hover state
    
    gradient_bg_hover.xml
    
    
      
    
    list_selector.xml – Actual liststyle which combines the above two styles
    
    list_selector.xml
    
    
        
     
        
     
        
    
    image_bg.xml – is for white border around the image in listview
    
    image_bg.xml
    
    
        
          
                
                
            
       
    
    3. Now open your main.xml file and define a listview in it.
    
    main.xml
    
    
     
        
     
    

    4. Next step is to design single listrow. Create a new XML file under layout folder and name it aslist_row.xml.
    Right Click ⇒ New ⇒ Android XML File

    In this tutorial I custom designed a listview which contains an image on leftside, time and arrow at the right end and a title in middle. I used RelativeLayout as parent node and placed all the remaining items using relative positioning properties. Check the following image

    List_row.xml – Single ListRow Layout

    list_row.xml
    
    
     
        
        
     
            
     
        
     
        
        
     
        
        
     
        
        
     
         
         
     
    

    The above XML will provide you output like below

    5. Until now we completed designing part of the listview. Next step is to parse the xml and update the data into listview. Create a new java class file in your src folder. Right Click on src ⇒ New ⇒ Class and name it as LazyAdapter.java

    LazyAdapter.java
    package com.example.androidhive;
     
    import java.util.ArrayList;
    import java.util.HashMap;
     
    import android.app.Activity;
    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;
     
    public class LazyAdapter extends BaseAdapter {
     
        private Activity activity;
        private ArrayList<HashMap<String, String>> data;
        private static LayoutInflater inflater=null;
        public ImageLoader imageLoader; 
     
        public LazyAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
            activity = a;
            data=d;
            inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            imageLoader=new ImageLoader(activity.getApplicationContext());
        }
     
        public int getCount() {
            return data.size();
        }
     
        public Object getItem(int position) {
            return position;
        }
     
        public long getItemId(int position) {
            return position;
        }
     
        public View getView(int position, View convertView, ViewGroup parent) {
            View vi=convertView;
            if(convertView==null)
                vi = inflater.inflate(R.layout.list_row, null);
     
            TextView title = (TextView)vi.findViewById(R.id.title); // title
            TextView artist = (TextView)vi.findViewById(R.id.artist); // artist name
            TextView duration = (TextView)vi.findViewById(R.id.duration); // duration
            ImageView thumb_image=(ImageView)vi.findViewById(R.id.list_image); // thumb image
     
            HashMap<String, String> song = new HashMap<String, String>();
            song = data.get(position);
     
            // Setting all values in listview
            title.setText(song.get(CustomizedListView.KEY_TITLE));
            artist.setText(song.get(CustomizedListView.KEY_ARTIST));
            duration.setText(song.get(CustomizedListView.KEY_DURATION));
            imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL), thumb_image);
            return vi;
        }
    }

    6. Now open your MainActivity class and type the following code. In the following code I am getting xml from url and parsing it. While parsing I am storing all the xml data into HashMap and finally I am passing HashMap to LazyAdapter class.

    CustomizedListView.java
    package com.example.androidhive;
     
    import java.util.ArrayList;
    import java.util.HashMap;
     
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.NodeList;
     
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.AdapterView.OnItemClickListener;
    import android.widget.ListView;
     
    public class CustomizedListView extends Activity {
        // All static variables
        static final String URL = "http://api.androidhive.info/music/music.xml";
        // XML node keys
        static final String KEY_SONG = "song"; // parent node
        static final String KEY_ID = "id";
        static final String KEY_TITLE = "title";
        static final String KEY_ARTIST = "artist";
        static final String KEY_DURATION = "duration";
        static final String KEY_THUMB_URL = "thumb_url";
     
        ListView list;
        LazyAdapter adapter;
     
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
     
            ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
     
            XMLParser parser = new XMLParser();
            String xml = parser.getXmlFromUrl(URL); // getting XML from URL
            Document doc = parser.getDomElement(xml); // getting DOM element
     
            NodeList nl = doc.getElementsByTagName(KEY_SONG);
            // looping through all song nodes <song>
            for (int I = 0; I < nl.getLength(); i++) {
                // creating new HashMap
                HashMap<String, String> map = new HashMap<String, String>();
                Element e = (Element) nl.item(i);
                // adding each child node to HashMap key => value
                map.put(KEY_ID, parser.getValue(e, KEY_ID));
                map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
                map.put(KEY_ARTIST, parser.getValue(e, KEY_ARTIST));
                map.put(KEY_DURATION, parser.getValue(e, KEY_DURATION));
                map.put(KEY_THUMB_URL, parser.getValue(e, KEY_THUMB_URL));
     
                // adding HashList to ArrayList
                songsList.add(map);
            }
     
            list=(ListView)findViewById(R.id.list);
     
            // Getting adapter by passing xml data ArrayList
            adapter=new LazyAdapter(this, songsList);
            list.setAdapter(adapter);
     
            // Click event for single list row
            list.setOnItemClickListener(new OnItemClickListener() {
     
                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                        int position, long id) {
     
                }
            });
        }
    }

    Add Permissions in AndroidManifest.xml

    Open your AndroidManifest.xml file add two permissons INTERNET andWRITE_EXTERNAL_STORAGE.

    AndroidManifest.xml
    
    
        
     
        
            
                
                    
                    
                
            
        
     
        
        
    

    Also you need 5 more classes in order to run this project. I am giving the code for each class at the end of the article. After adding all the classes if you run the project it will show output like below
    ListView Default State

    ListView on Select State

    Other Classes you needed to run this project

    You also need to include following class which deals functionalities like fetching images from WEB, storing them in cache and clearing cache etc., Make sure that you included following files in your project.

    XMLParser.java

    XMLParser.java
    package com.example.androidhive;
     
    import java.io.IOException;
    import java.io.StringReader;
    import java.io.UnsupportedEncodingException;
     
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
     
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.util.EntityUtils;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
     
    import android.util.Log;
     
    public class XMLParser {
     
        // constructor
        public XMLParser() {
     
        }
     
        /**
         * Getting XML from URL making HTTP request
         * @param url string
         * */
        public String getXmlFromUrl(String url) {
            String xml = null;
     
            try {
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost(url);
     
                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                xml = EntityUtils.toString(httpEntity);
     
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            // return XML
            return xml;
        }
     
        /**
         * Getting XML DOM element
         * @param XML string
         * */
        public Document getDomElement(String xml){
            Document doc = null;
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            try {
     
                DocumentBuilder db = dbf.newDocumentBuilder();
     
                InputSource is = new InputSource();
                    is.setCharacterStream(new StringReader(xml));
                    doc = db.parse(is); 
     
                } catch (ParserConfigurationException e) {
                    Log.e("Error: ", e.getMessage());
                    return null;
                } catch (SAXException e) {
                    Log.e("Error: ", e.getMessage());
                    return null;
                } catch (IOException e) {
                    Log.e("Error: ", e.getMessage());
                    return null;
                }
     
                return doc;
        }
     
        /** Getting node value
          * @param elem element
          */
         public final String getElementValue( Node elem ) {
             Node child;
             if( elem != null){
                 if (elem.hasChildNodes()){
                     for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){
                         if( child.getNodeType() == Node.TEXT_NODE  ){
                             return child.getNodeValue();
                         }
                     }
                 }
             }
             return "";
         }
     
         /**
          * Getting node value
          * @param Element node
          * @param key string
          * */
         public String getValue(Element item, String str) {
                NodeList n = item.getElementsByTagName(str);
                return this.getElementValue(n.item(0));
            }
    }

    ImageLoader.java

    ImageLoader.java
    package com.example.androidhive;
     
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.Collections;
    import java.util.Map;
    import java.util.WeakHashMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.widget.ImageView;
     
    public class ImageLoader {
     
        MemoryCache memoryCache=new MemoryCache();
        FileCache fileCache;
        private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
        ExecutorService executorService; 
     
        public ImageLoader(Context context){
            fileCache=new FileCache(context);
            executorService=Executors.newFixedThreadPool(5);
        }
     
        final int stub_id = R.drawable.no_image;
        public void DisplayImage(String url, ImageView imageView)
        {
            imageViews.put(imageView, url);
            Bitmap bitmap=memoryCache.get(url);
            if(bitmap!=null)
                imageView.setImageBitmap(bitmap);
            else
            {
                queuePhoto(url, imageView);
                imageView.setImageResource(stub_id);
            }
        }
     
        private void queuePhoto(String url, ImageView imageView)
        {
            PhotoToLoad p=new PhotoToLoad(url, imageView);
            executorService.submit(new PhotosLoader(p));
        }
     
        private Bitmap getBitmap(String url)
        {
            File f=fileCache.getFile(url);
     
            //from SD cache
            Bitmap b = decodeFile(f);
            if(b!=null)
                return b;
     
            //from web
            try {
                Bitmap bitmap=null;
                URL imageUrl = new URL(url);
                HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
                conn.setConnectTimeout(30000);
                conn.setReadTimeout(30000);
                conn.setInstanceFollowRedirects(true);
                InputStream is=conn.getInputStream();
                OutputStream os = new FileOutputStream(f);
                Utils.CopyStream(is, os);
                os.close();
                bitmap = decodeFile(f);
                return bitmap;
            } catch (Exception ex){
               ex.printStackTrace();
               return null;
            }
        }
     
        //decodes image and scales it to reduce memory consumption
        private Bitmap decodeFile(File f){
            try {
                //decode image size
                BitmapFactory.Options o = new BitmapFactory.Options();
                o.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(new FileInputStream(f),null,o);
     
                //Find the correct scale value. It should be the power of 2.
                final int REQUIRED_SIZE=70;
                int width_tmp=o.outWidth, height_tmp=o.outHeight;
                int scale=1;
                while(true){
                    if(width_tmp/2<REQUIRED_SIZE 				
    loading Đang tải...

    template được ưa chuộng