下载问题

我现在想要用android的listview来显示从服务器上下载的图片该怎么做?像图片中这样

第一步:分析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代码
/**
* @see android.widget.Adapter#getView(int, View, ViewGroup)
/

public View getView(int position, View convertView, ViewGroup parent) {

return createViewFromResource(position, convertView, parent, mResource);

}

/
*
* @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代码
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;    
 }   

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代码
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");    
                 }    
             }    
         }    
     }    
 }   

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代码
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));

}

}

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代码
public void setViewImage(ImageView v, String value) {

Bitmap bitmap = WebImageBuilder.returnBitMap(value);

((ImageView) v).setImageBitmap(bitmap);

}

public void setViewImage(ImageView v, String value) {
Bitmap bitmap = WebImageBuilder.returnBitMap(value);
((ImageView) v).setImageBitmap(bitmap);
}我们用Bitmap 来对ImageView进行设置,WebImageBuilder.returnBitMap是我自己实现的获取网络图片的方法,当然google下都是的,在我下面的源码中也有,在这里就不多说了!说到这,我的解释也就说完了,希望可以给你帮助!如果你是不愿意跟着别人思路走的人,希望自己研究出来的话,那最后我也拿我的源码贴上,对有些朋友来说获取直接看源码,理解的更快吧!

最后强调一下,本文为胡乐费的原创,如果要转载的话,希望注明出处!