android ListView顯示網絡圖片


研究了android兩個禮拜,稍微有了點眉目,開始正式幫公司開發應用的時候,發現ListView沒有現成的顯示網絡圖片的類或方法,網上查了查也沒找到好的解決方法。心一橫,自己研究吧,現在把我的解決辦法和大家分享一下。

 

使用ListView的方法就不在此介紹了,google一下都是的。

 

第一步:分析api

使用ListView都需要使用Adapter,而api中的adapter都繼承自BaseAdapter,所以第一反應就是自己實現一個繼承自BaseAdapter的adapter,但是BaseAdapter還是屬於高度抽象的基類,所以實現起來還是還是有點難度的。此時作為初學者的你(當然我也是啦)應該最熟悉的是SimpleAdapter了吧,而且SimpleAdapter也可以實現在ListView顯示圖片,但是就是不能顯示網絡圖片,只能顯示在drawalbe中定義過的圖片。所以就想,我是否可以改寫SimpleAdapter的類,在它實例化drawalbe中圖片時,我替換成我自己 的顯示網絡圖片的方法呢?答案是肯定的!(想獲取android的源碼,可以查看我的另一篇文章http://hulefei29.iteye.com/blog/615016

 

第二步:源碼分析

經過查看源碼SimpleAdapter發現,顯示每個item視圖都是通過調用(int position, View convertView, ViewGroup parent)方法來實現的

Java代碼 復制代碼  收藏代碼
  1. /**  
  2.      * @see android.widget.Adapter#getView(int, View, ViewGroup)  
  3.      */  
  4.     public View getView(int position, View convertView, ViewGroup parent) {   
  5.         return createViewFromResource(position, convertView, parent, mResource);   
  6.     }  
/**
     * @see android.widget.Adapter#getView(int, View, ViewGroup)
     */
    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }

 

在getView(int position, View convertView, ViewGroup parent)中又調用了SimpleAdapter的私有方法createViewFromResource來組裝View,在createViewFromResource中對SimpleAdapter的參數String[] from

和int[] to進行了組裝,代碼如下:

Java代碼 復制代碼  收藏代碼
  1. private View createViewFromResource(int position, View convertView,   
  2.             ViewGroup parent, int resource) {   
  3.         View v;   
  4.         if (convertView == null) {   
  5.             v = mInflater.inflate(resource, parent, false);   
  6.   
  7.             final int[] to = mTo;   
  8.             final int count = to.length;   
  9.             final View[] holder = new View[count];   
  10.   
  11.             for (int i = 0; i < count; i++) {   
  12.                 holder[i] = v.findViewById(to[i]);   
  13.             }   
  14.   
  15.             v.setTag(holder);   
  16.         } else {   
  17.             v = convertView;   
  18.         }   
  19.   
  20.         bindView(position, v);   
  21.   
  22.         return v;   
  23.     }  
private View createViewFromResource(int position, View convertView,
            ViewGroup parent, int resource) {
        View v;
        if (convertView == null) {
            v = mInflater.inflate(resource, parent, false);

            final int[] to = mTo;
            final int count = to.length;
            final View[] holder = new View[count];

            for (int i = 0; i < count; i++) {
                holder[i] = v.findViewById(to[i]);
            }

            v.setTag(holder);
        } else {
            v = convertView;
        }

        bindView(position, v);

        return v;
    }

 

在createViewFromResource方法中又有一個bindView(position, v)方法對item中的各個View進行了組裝,bindView(position, v)代碼如下:

Java代碼 復制代碼  收藏代碼
  1. private void bindView(int position, View view) {   
  2.         final Map dataSet = mData.get(position);   
  3.         if (dataSet == null) {   
  4.             return;   
  5.         }   
  6.   
  7.         final ViewBinder binder = mViewBinder;   
  8.         final View[] holder = (View[]) view.getTag();   
  9.         final String[] from = mFrom;   
  10.         final int[] to = mTo;   
  11.         final int count = to.length;   
  12.   
  13.         for (int i = 0; i < count; i++) {   
  14.             final View v = holder[i];   
  15.             if (v != null) {   
  16.                 final Object data = dataSet.get(from[i]);   
  17.                 String text = data == null ? "" : data.toString();   
  18.                 if (text == null) {   
  19.                     text = "";   
  20.                 }   
  21.   
  22.                 boolean bound = false;   
  23.                 if (binder != null) {   
  24.                     bound = binder.setViewValue(v, data, text);   
  25.                 }   
  26.   
  27.                 if (!bound) {   
  28.                     if (v instanceof Checkable) {   
  29.                         if (data instanceof Boolean) {   
  30.                             ((Checkable) v).setChecked((Boolean) data);   
  31.                         } else {   
  32.                             throw new IllegalStateException(v.getClass().getName() +   
  33.                                     " should be bound to a Boolean, not a " + data.getClass());   
  34.                         }   
  35.                     } else if (v instanceof TextView) {   
  36.                         // Note: keep the instanceof TextView check at the bottom of these   
  37.                         // ifs since a lot of views are TextViews (e.g. CheckBoxes).   
  38.                         setViewText((TextView) v, text);   
  39.                     } else if (v instanceof ImageView) {   
  40.                                if (data instanceof Integer) {   
  41.                             setViewImage((ImageView) v, (Integer) data);                               
  42.                         } else {   
  43.                             setViewImage((ImageView) v, text);   
  44.                         }   
  45.                     } else {   
  46.                         throw new IllegalStateException(v.getClass().getName() + " is not a " +   
  47.                                 " view that can be bounds by this SimpleAdapter");   
  48.                     }   
  49.                 }   
  50.             }   
  51.         }   
  52.     }  
private void bindView(int position, View view) {
        final Map dataSet = mData.get(position);
        if (dataSet == null) {
            return;
        }

        final ViewBinder binder = mViewBinder;
        final View[] holder = (View[]) view.getTag();
        final String[] from = mFrom;
        final int[] to = mTo;
        final int count = to.length;

        for (int i = 0; i < count; i++) {
            final View v = holder[i];
            if (v != null) {
                final Object data = dataSet.get(from[i]);
                String text = data == null ? "" : data.toString();
                if (text == null) {
                    text = "";
                }

                boolean bound = false;
                if (binder != null) {
                    bound = binder.setViewValue(v, data, text);
                }

                if (!bound) {
                    if (v instanceof Checkable) {
                        if (data instanceof Boolean) {
                            ((Checkable) v).setChecked((Boolean) data);
                        } else {
                            throw new IllegalStateException(v.getClass().getName() +
                                    " should be bound to a Boolean, not a " + data.getClass());
                        }
                    } else if (v instanceof TextView) {
                        // Note: keep the instanceof TextView check at the bottom of these
                        // ifs since a lot of views are TextViews (e.g. CheckBoxes).
                        setViewText((TextView) v, text);
                    } else if (v instanceof ImageView) {
                               if (data instanceof Integer) {
                            setViewImage((ImageView) v, (Integer) data);                            
                        } else {
                            setViewImage((ImageView) v, text);
                        }
                    } else {
                        throw new IllegalStateException(v.getClass().getName() + " is not a " +
                                " view that can be bounds by this SimpleAdapter");
                    }
                }
            }
        }
    }

 
終於找到了對ViewImage進行組裝的代碼了“else if (v instanceof ImageView)”,我們留成功之差一步之遙了!

看到上面茫茫的代碼是不是已經頭暈了呢,其實以上的都是源代碼,我沒有做過任何的修改,也不需要修改,只是需要把它從SimpleAdapter中取出來進行覆蓋,以為他們私有方法,不能用super調用!到最后終於到你出手的時候了,你需要重寫SimpleAdapter類中的setViewText方法,SimpleAdapter對setViewText進行了重載,有兩個方法,代碼如下:

Java代碼 復制代碼  收藏代碼
  1. public void setViewImage(ImageView v, int value) {   
  2.     v.setImageResource(value);   
  3. }   
  4.   
  5.   
  6. public void setViewImage(ImageView v, String value) {   
  7.     try {   
  8.         v.setImageResource(Integer.parseInt(value));   
  9.     } catch (NumberFormatException nfe) {   
  10.         v.setImageURI(Uri.parse(value));   
  11.     }   
  12. }  
    public void setViewImage(ImageView v, int value) {
        v.setImageResource(value);
    }

   
    public void setViewImage(ImageView v, String value) {
        try {
            v.setImageResource(Integer.parseInt(value));
        } catch (NumberFormatException nfe) {
            v.setImageURI(Uri.parse(value));
        }
    }

 setViewImage(ImageView v, int value) 你應該一看就熟悉了吧,int就是R中的索引值,但是你還看到SimpleAdapter居然還有一個setViewImage(ImageView v, String value)可以接受String的方法,在往下看就是知道了,如果不是索引,ImageView 也可以接受Uri的值來設置圖片,切忌Uri不是Url,所以我們只需要改寫一下這個方法就ok了,代碼如下:

Java代碼 復制代碼  收藏代碼
  1. public void setViewImage(ImageView v, String value) {   
  2.         Bitmap bitmap = WebImageBuilder.returnBitMap(value);   
  3.         ((ImageView) v).setImageBitmap(bitmap);   
  4.     }  
public void setViewImage(ImageView v, String value) {
    	Bitmap bitmap = WebImageBuilder.returnBitMap(value);
    	((ImageView) v).setImageBitmap(bitmap);
    }

 我們用Bitmap 來對ImageView進行設置,WebImageBuilder.returnBitMap是我自己實現的獲取網絡圖片的方法,當然google下都是的,在我下面的源碼中也有,在這里就不多說了!說到這,我的解釋也就說完了,希望可以給你幫助!如果你是不願意跟着別人思路走的人,希望自己研究出來的話,那最后我也拿我的源碼貼上,對有些朋友來說獲取直接看源碼,理解的更快吧!

 

最后強調一下,本文為胡樂費的原創,如果要轉載的話,希望注明出處!

本文轉自: http://hulefei29.iteye.com/blog/616262


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM