异步加载图片
2015-08-17 11:05
381 查看
实现效果:
1、异步加载图片,在加载图片时,先加载一个默认的图片,然后在后台加载图片,加载完成后显示出来;
2、当用户在滑动时,停止加载图片的线程,当停止滑动时,看哪几个ITEM在显示屏内,只加载这几个,其它线程保持阻止;(下篇再讲)
效果图:
刚开始加载时 向下划动(新划出来的是空白块) 停划,加载完成
![](http://img.blog.csdn.net/20140102211823687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFydmljODgwOTI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20140102211827031?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFydmljODgwOTI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20140102211832781?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaGFydmljODgwOTI1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
[html] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
[html] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="70.0dip"
android:background="@drawable/item"
android:drawingCacheQuality="high"
android:minHeight="70.0dip"
android:orientation="horizontal" >
<ImageView
android:id="@+id/sItemIcon"
android:layout_width="42.0dip"
android:layout_height="54.0dip"
android:layout_margin="10.0dip"
android:background="@drawable/rc_item_bg"
android:padding="2.0dip"
android:scaleType="fitXY" />
<TextView
android:text="斗破苍穹"
android:id="@+id/sItemTitle"
android:layout_width="fill_parent"
android:layout_height="30.0dip"
android:layout_alignTop="@+id/sItemIcon"
android:layout_toRightOf="@+id/sItemIcon"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="#ffffff"
android:textSize="18.0sp" />
</RelativeLayout>
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
package cn.wangmeng.test;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
public class AsyncListImage extends Activity {
private ListView list;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list=(ListView)findViewById(R.id.list);
List<ImageAndText> dataArray=new ArrayList<ImageAndText>();
for (int i = 0; i < 100; i++) {
ImageAndText test=new ImageAndText("http://www.wangmeng.cn/images/logo.gif", "test");
ImageAndText test1=new ImageAndText("http://www.pfwx.com/files/article/image/0/54/54s.jpg", "test1");
ImageAndText test2=new ImageAndText("http://www.pfwx.com/files/article/image/0/4/4s.jpg","test2");
ImageAndText test3=new ImageAndText("http://www.pfwx.com/files/article/image/9/9760/9760s.jpg","test3");
ImageAndText test4=new ImageAndText("http://www.pfwx.com/files/article/image/3/3382/3382s.jpg","test4");
ImageAndText test5=new ImageAndText("http://www.pfwx.com/files/article/image/3/3237/3237s.jpg","test5");
dataArray.add(test);
dataArray.add(test1);
dataArray.add(test2);
dataArray.add(test3);
dataArray.add(test4);
dataArray.add(test5);
}
ImageAndTextListAdapter adapter=new ImageAndTextListAdapter(this, dataArray, list);
list.setAdapter(adapter);
}
}
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
package cn.wangmeng.test;
public class ImageAndText {
private String imageUrl;
private String text;
public ImageAndText(String imageUrl, String text) {
this.imageUrl = imageUrl;
this.text = text;
}
public String getImageUrl() {
return imageUrl;
}
public String getText() {
return text;
}
}
上面两个代码一块讲
1、ImageAndText类是用来存储要与XML绑定的图片地址和名字地址的。
2、将所有的地址都放在一个List里面(dataArray),然后将其传入ImageAndTextListAdapter()函数中;可见这个ImageAndTextListAdapter()函数是根据传进去的dataArray生成对应的Adapter的
3、然后将ImageAndTextListAdapter()返回的Adapter与listView绑定
这是重写于baseAdapter的类,由于重写于baseAdapter,所以有几个必须重写的函数,getCount()、getItem()、getItemId()、getView(),我们先把总体代码写出来,只讲一个getView()函数,其实函数就不讲了,先着重说下getView()函数在什么时候被系统调用:
getView()函数在什么时候被系统调用:
注意一点是android系统在显示列表时,并不是把所有代表都显示出来,让你随便划,划到哪是哪;而是根据当前的在划到的ITEM,调用当前ITEM的getView()来显示它。
全部代码:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
package cn.wangmeng.test;
import java.util.ArrayList;
import java.util.List;
import cn.wangmeng.test.AsyncImageLoader.ImageCallback;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class ImageAndTextListAdapter extends BaseAdapter {
private LayoutInflater inflater;
private ListView listView;
private AsyncImageLoader asyncImageLoader;
private List<ImageAndText> dataArray=new ArrayList<ImageAndText>();
public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {
this.listView = listView;
asyncImageLoader = new AsyncImageLoader();
inflater = activity.getLayoutInflater();
dataArray=imageAndTexts;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return dataArray.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
if(position >= getCount()){
return null;
}
return dataArray.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//不需要ViewHolder版,直接将ImageAndText与XML资源关联起来
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.book_item_adapter, null);
}
convertView.setTag(position);
ImageAndText imageAndText = (ImageAndText) getItem(position);
String imageUrl = imageAndText.getImageUrl();
TextView textView = (TextView) convertView.findViewById(R.id.sItemTitle);
// 将XML视图项与用户输入的URL和文本在绑定
textView.setText(imageAndText.getText());//加载TEXT
ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);//在初始化时,先把背景图片设置成默认背景,
//否则在下拉时会随机匹配背景,不美观
asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
@Override
public void onImageLoad(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundDrawable(drawable);
}
}
//加载不成功的图片处理
@Override
public void onError(Integer pos) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);
}
}
});
return convertView;
}
}
我们着重看getView()函数
1、看这段:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
if (convertView == null) {
convertView = inflater.inflate(R.layout.book_item_adapter, null);
}
convertView.setTag(position);
ImageAndText imageAndText = (ImageAndText) getItem(position);
String imageUrl = imageAndText.getImageUrl();
TextView textView = (TextView) convertView.findViewById(R.id.sItemTitle);
// 将XML视图项与用户输入的URL和文本在绑定
textView.setText(imageAndText.getText());//加载TEXT
ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);
这段代码没什么特别的就是将前面dataArray的信息与XML的元素项对应起来,并绑定,最关键的是下面这段,下面这个方法才是实现异步加载图片的关键:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
@Override
public void onImageLoad(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundDrawable(drawable);
}
}
//加载不成功的图片处理
@Override
public void onError(Integer pos) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);
}
}
});
这段代码的奇特之处在于,利用AsyncImageLoader类的实例(asyncImageLoader),调用方法loadDrawable()方法,就实现了加载后图像的绑定;好神奇,仔细看他是怎么做到的。这里先注意的有两点:
(1)、传进去的参数,当前项的位置(position),当前图片的URL(imageUrl),一个名称为ImageCallback()接口函数;
(2)、ImageCallback()接口函数里的两个被重写的函数onImageLoad()和onError()
从上面的讲解也应该能猜到这个类,主要的功能就是加载图片,然后成功后更新UI;
先看全部代码,然后再逐步讲
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
package cn.wangmeng.test;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
public class AsyncImageLoader {
final Handler handler = new Handler();
private HashMap<String, SoftReference<Drawable>> imageCache;
public AsyncImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();//图片缓存
}
// 回调函数
public interface ImageCallback {
public void onImageLoad(Integer t, Drawable drawable);
public void onError(Integer t);
}
public Drawable loadDrawable(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
new Thread() {
@Override
public void run() {
LoadImg(pos, imageUrl, imageCallback);
}
}.start();
return null;
}// loadDrawable---end
public void LoadImg(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
// 首先判断是否在缓存中
// 但有个问题是:ImageCache可能会越来越大,以至用户内存用光,所以要用SoftReference(弱引用)来实现
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
}
// 尝试从URL中加载
try {
final Drawable drawable = loadImageFromUrl(imageUrl);
if (drawable != null) {
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
}
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onError(pos);
}
});
e.printStackTrace();
}
}
// 根据URL加载图片,如果出现错误throws IOException式的错误,以便在LoadImg中捕获,执行OnError()函数
public static Drawable loadImageFromUrl(String url) throws IOException {
URL m;
InputStream i = null;
m = new URL(url);
i = (InputStream) m.getContent();
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
}
分别讲解
1、先看这段代码
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
// 回调函数
public interface ImageCallback {
public void onImageLoad(Integer t, Drawable drawable);
public void onError(Integer t);
}
public Drawable loadDrawable(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
new Thread() {
@Override
public void run() {
LoadImg(pos, imageUrl, imageCallback);
}
}.start();
return null;
}// loadDrawable---end
(1)首先注意,刚才我们调用的loadDrawable()函数,里面初始化并运行了一个线程,而这个线程的里面只有一个函数LoadImg(),对于这个函数下面我们具体讲,它的主要功能就是加载图片,然后更新UI
(2)上面也看出了ImageCallback是一个接口,而里面的两个函数onImageLoad()和onError()在这里是没有具体实现的,那在哪里实现呢,当然是我们上面的ImageAndTextListAdapter.java里面了,等下我们具体会再讲。
再往下看
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
// 根据URL加载图片,如果出现错误throws IOException式的错误,以便在LoadImg中捕获,执行OnError()函数
public static Drawable loadImageFromUrl(String url) throws IOException {
URL m;
InputStream i = null;
m = new URL(url);
i = (InputStream) m.getContent();
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
public void LoadImg(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
// 首先判断是否在缓存中
// 但有个问题是:ImageCache可能会越来越大,以至用户内存用光,所以要用SoftReference(弱引用)来实现
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
}
// 尝试从URL中加载
try {
final Drawable drawable = loadImageFromUrl(imageUrl);
if (drawable != null) {
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
}
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onError(pos);
}
});
e.printStackTrace();
}
}
(1)、loadImageFromUrl()函数,就是根据URL到网上加载图片,然后返回图片流Drawable类型变量
(2)、对于LoadImg()我们再拆一下,先看如何在缓存中加载
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
}
注意:
1、在这里就已经得到了图像
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
2、得到图像之后就到了这段代码:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
当我们得到图像之后,调用imageCallback.onImageLoad(pos, drawable);来更新UI,由于我们再回来看看ImageAndTextListAdapter.java中的代码
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
@Override
public void onImageLoad(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundDrawable(drawable);
}
}
});
看到了吧,就是把得到的drawable与加载到UI中!!!!这就实现了回调
OK,就到这吧,OnError()的原理一样,只不过是对程序没有加载到图片时应该怎么处理,其实就是当没有加载到图片时就是默认图片代替。
1、异步加载图片,在加载图片时,先加载一个默认的图片,然后在后台加载图片,加载完成后显示出来;
2、当用户在滑动时,停止加载图片的线程,当停止滑动时,看哪几个ITEM在显示屏内,只加载这几个,其它线程保持阻止;(下篇再讲)
效果图:
刚开始加载时 向下划动(新划出来的是空白块) 停划,加载完成
一、XML
1、main.xml
[html] viewplaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
2、列表子项XML(book_item_adapter.xml)
[html] viewplaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="70.0dip"
android:background="@drawable/item"
android:drawingCacheQuality="high"
android:minHeight="70.0dip"
android:orientation="horizontal" >
<ImageView
android:id="@+id/sItemIcon"
android:layout_width="42.0dip"
android:layout_height="54.0dip"
android:layout_margin="10.0dip"
android:background="@drawable/rc_item_bg"
android:padding="2.0dip"
android:scaleType="fitXY" />
<TextView
android:text="斗破苍穹"
android:id="@+id/sItemTitle"
android:layout_width="fill_parent"
android:layout_height="30.0dip"
android:layout_alignTop="@+id/sItemIcon"
android:layout_toRightOf="@+id/sItemIcon"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="#ffffff"
android:textSize="18.0sp" />
</RelativeLayout>
二、JAVA代码
1、主页面代码(AsyncListImage.java)
[java] viewplaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
package cn.wangmeng.test;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
public class AsyncListImage extends Activity {
private ListView list;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
list=(ListView)findViewById(R.id.list);
List<ImageAndText> dataArray=new ArrayList<ImageAndText>();
for (int i = 0; i < 100; i++) {
ImageAndText test=new ImageAndText("http://www.wangmeng.cn/images/logo.gif", "test");
ImageAndText test1=new ImageAndText("http://www.pfwx.com/files/article/image/0/54/54s.jpg", "test1");
ImageAndText test2=new ImageAndText("http://www.pfwx.com/files/article/image/0/4/4s.jpg","test2");
ImageAndText test3=new ImageAndText("http://www.pfwx.com/files/article/image/9/9760/9760s.jpg","test3");
ImageAndText test4=new ImageAndText("http://www.pfwx.com/files/article/image/3/3382/3382s.jpg","test4");
ImageAndText test5=new ImageAndText("http://www.pfwx.com/files/article/image/3/3237/3237s.jpg","test5");
dataArray.add(test);
dataArray.add(test1);
dataArray.add(test2);
dataArray.add(test3);
dataArray.add(test4);
dataArray.add(test5);
}
ImageAndTextListAdapter adapter=new ImageAndTextListAdapter(this, dataArray, list);
list.setAdapter(adapter);
}
}
2、ImageAndText.java
[java] viewplaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
package cn.wangmeng.test;
public class ImageAndText {
private String imageUrl;
private String text;
public ImageAndText(String imageUrl, String text) {
this.imageUrl = imageUrl;
this.text = text;
}
public String getImageUrl() {
return imageUrl;
}
public String getText() {
return text;
}
}
上面两个代码一块讲
1、ImageAndText类是用来存储要与XML绑定的图片地址和名字地址的。
2、将所有的地址都放在一个List里面(dataArray),然后将其传入ImageAndTextListAdapter()函数中;可见这个ImageAndTextListAdapter()函数是根据传进去的dataArray生成对应的Adapter的
3、然后将ImageAndTextListAdapter()返回的Adapter与listView绑定
3、ImageAndTextListAdapter.java
这是重写于baseAdapter的类,由于重写于baseAdapter,所以有几个必须重写的函数,getCount()、getItem()、getItemId()、getView(),我们先把总体代码写出来,只讲一个getView()函数,其实函数就不讲了,先着重说下getView()函数在什么时候被系统调用:getView()函数在什么时候被系统调用:
注意一点是android系统在显示列表时,并不是把所有代表都显示出来,让你随便划,划到哪是哪;而是根据当前的在划到的ITEM,调用当前ITEM的getView()来显示它。
全部代码:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
package cn.wangmeng.test;
import java.util.ArrayList;
import java.util.List;
import cn.wangmeng.test.AsyncImageLoader.ImageCallback;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class ImageAndTextListAdapter extends BaseAdapter {
private LayoutInflater inflater;
private ListView listView;
private AsyncImageLoader asyncImageLoader;
private List<ImageAndText> dataArray=new ArrayList<ImageAndText>();
public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {
this.listView = listView;
asyncImageLoader = new AsyncImageLoader();
inflater = activity.getLayoutInflater();
dataArray=imageAndTexts;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return dataArray.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
if(position >= getCount()){
return null;
}
return dataArray.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//不需要ViewHolder版,直接将ImageAndText与XML资源关联起来
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.book_item_adapter, null);
}
convertView.setTag(position);
ImageAndText imageAndText = (ImageAndText) getItem(position);
String imageUrl = imageAndText.getImageUrl();
TextView textView = (TextView) convertView.findViewById(R.id.sItemTitle);
// 将XML视图项与用户输入的URL和文本在绑定
textView.setText(imageAndText.getText());//加载TEXT
ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);//在初始化时,先把背景图片设置成默认背景,
//否则在下拉时会随机匹配背景,不美观
asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
@Override
public void onImageLoad(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundDrawable(drawable);
}
}
//加载不成功的图片处理
@Override
public void onError(Integer pos) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);
}
}
});
return convertView;
}
}
我们着重看getView()函数
1、看这段:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
if (convertView == null) {
convertView = inflater.inflate(R.layout.book_item_adapter, null);
}
convertView.setTag(position);
ImageAndText imageAndText = (ImageAndText) getItem(position);
String imageUrl = imageAndText.getImageUrl();
TextView textView = (TextView) convertView.findViewById(R.id.sItemTitle);
// 将XML视图项与用户输入的URL和文本在绑定
textView.setText(imageAndText.getText());//加载TEXT
ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);
这段代码没什么特别的就是将前面dataArray的信息与XML的元素项对应起来,并绑定,最关键的是下面这段,下面这个方法才是实现异步加载图片的关键:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
@Override
public void onImageLoad(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundDrawable(drawable);
}
}
//加载不成功的图片处理
@Override
public void onError(Integer pos) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundResource(R.drawable.rc_item_bg);
}
}
});
这段代码的奇特之处在于,利用AsyncImageLoader类的实例(asyncImageLoader),调用方法loadDrawable()方法,就实现了加载后图像的绑定;好神奇,仔细看他是怎么做到的。这里先注意的有两点:
(1)、传进去的参数,当前项的位置(position),当前图片的URL(imageUrl),一个名称为ImageCallback()接口函数;
(2)、ImageCallback()接口函数里的两个被重写的函数onImageLoad()和onError()
3、AsyncImageLoader.java
从上面的讲解也应该能猜到这个类,主要的功能就是加载图片,然后成功后更新UI;先看全部代码,然后再逐步讲
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
package cn.wangmeng.test;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
public class AsyncImageLoader {
final Handler handler = new Handler();
private HashMap<String, SoftReference<Drawable>> imageCache;
public AsyncImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();//图片缓存
}
// 回调函数
public interface ImageCallback {
public void onImageLoad(Integer t, Drawable drawable);
public void onError(Integer t);
}
public Drawable loadDrawable(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
new Thread() {
@Override
public void run() {
LoadImg(pos, imageUrl, imageCallback);
}
}.start();
return null;
}// loadDrawable---end
public void LoadImg(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
// 首先判断是否在缓存中
// 但有个问题是:ImageCache可能会越来越大,以至用户内存用光,所以要用SoftReference(弱引用)来实现
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
}
// 尝试从URL中加载
try {
final Drawable drawable = loadImageFromUrl(imageUrl);
if (drawable != null) {
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
}
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onError(pos);
}
});
e.printStackTrace();
}
}
// 根据URL加载图片,如果出现错误throws IOException式的错误,以便在LoadImg中捕获,执行OnError()函数
public static Drawable loadImageFromUrl(String url) throws IOException {
URL m;
InputStream i = null;
m = new URL(url);
i = (InputStream) m.getContent();
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
}
分别讲解
1、先看这段代码
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
// 回调函数
public interface ImageCallback {
public void onImageLoad(Integer t, Drawable drawable);
public void onError(Integer t);
}
public Drawable loadDrawable(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
new Thread() {
@Override
public void run() {
LoadImg(pos, imageUrl, imageCallback);
}
}.start();
return null;
}// loadDrawable---end
(1)首先注意,刚才我们调用的loadDrawable()函数,里面初始化并运行了一个线程,而这个线程的里面只有一个函数LoadImg(),对于这个函数下面我们具体讲,它的主要功能就是加载图片,然后更新UI
(2)上面也看出了ImageCallback是一个接口,而里面的两个函数onImageLoad()和onError()在这里是没有具体实现的,那在哪里实现呢,当然是我们上面的ImageAndTextListAdapter.java里面了,等下我们具体会再讲。
再往下看
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
// 根据URL加载图片,如果出现错误throws IOException式的错误,以便在LoadImg中捕获,执行OnError()函数
public static Drawable loadImageFromUrl(String url) throws IOException {
URL m;
InputStream i = null;
m = new URL(url);
i = (InputStream) m.getContent();
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
public void LoadImg(final Integer pos, final String imageUrl,
final ImageCallback imageCallback) {
// 首先判断是否在缓存中
// 但有个问题是:ImageCache可能会越来越大,以至用户内存用光,所以要用SoftReference(弱引用)来实现
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
}
// 尝试从URL中加载
try {
final Drawable drawable = loadImageFromUrl(imageUrl);
if (drawable != null) {
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
}
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
} catch (IOException e) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onError(pos);
}
});
e.printStackTrace();
}
}
(1)、loadImageFromUrl()函数,就是根据URL到网上加载图片,然后返回图片流Drawable类型变量
(2)、对于LoadImg()我们再拆一下,先看如何在缓存中加载
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
}
注意:
1、在这里就已经得到了图像
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
final Drawable drawable = softReference.get();
2、得到图像之后就到了这段代码:
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
if (drawable != null) {
handler.post(new Runnable() {
@Override
public void run() {
imageCallback.onImageLoad(pos, drawable);
}
});
return;
}
当我们得到图像之后,调用imageCallback.onImageLoad(pos, drawable);来更新UI,由于我们再回来看看ImageAndTextListAdapter.java中的代码
[java] view
plaincopy
![](https://code.csdn.net/assets/CODE_ico.png)
asyncImageLoader.loadDrawable(position,imageUrl, new ImageCallback() {
@Override
public void onImageLoad(Integer pos, Drawable drawable) {
View view = listView.findViewWithTag(pos);
if(view != null){
ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);
iv.setBackgroundDrawable(drawable);
}
}
});
看到了吧,就是把得到的drawable与加载到UI中!!!!这就实现了回调
OK,就到这吧,OnError()的原理一样,只不过是对程序没有加载到图片时应该怎么处理,其实就是当没有加载到图片时就是默认图片代替。
相关文章推荐
- 9秒学院总结Cocos2d-X面试题
- Toast使用方法
- ngx_lua 模块API说明
- jsp/servlet相关技术 (五) --- jsp内置对象(二)
- Linux进程间通信——使用信号
- 红黑树基本概念
- 让edittext控件显示圆角边框
- php session 购物车类
- db的操作
- UITableView(可滚动到顶部和底部)
- 串口发送
- 杭电OJ 5387 Clock
- 升级ZC451 codebase遇到的问题以及解决方法
- 中介者模式
- 质因数分解及算法实现
- MySQL-Linux安装
- matlab 画图
- ijkplayer阅读笔记06-音频流程
- vijos - P1319数列 (二进制 + 找规律 + python)
- string get_telno(string &userid) 和 string get_telno(string userid) 有什么区别