研究了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)方法來實現的
- /**
- * @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進行了組裝,代碼如下:
- 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)代碼如下:
- 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進行了重載,有兩個方法,代碼如下:
- 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了,代碼如下:
- 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下都是的,在我下面的源碼中也有,在這里就不多說了!說到這,我的解釋也就說完了,希望可以給你幫助!如果你是不願意跟着別人思路走的人,希望自己研究出來的話,那最后我也拿我的源碼貼上,對有些朋友來說獲取直接看源碼,理解的更快吧!
最后強調一下,本文為胡樂費的原創,如果要轉載的話,希望注明出處!