参考自 http://blog.csdn.net/wanglong0537/article/details/6334005#
http://www.cnblogs.com/slider/archive/2011/11/22/2258942.html
http://www.iteye.com/topic/685986
ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上异步加载图片主方法的代码:
package cn.wangmeng.test;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
public class AsyncImageLoader {
private HashMap<String, SoftReference<Drawable>> imageCache;
public AsyncImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};
new Thread() {
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));//把获得的drawable存入缓存
Message message = handler.obtainMessage(0, drawable);//obtainmessage()与new message类似
//obtainmessage()是从消息池拿来的一个msg,不必另开空间new
handler.sendMessage(message);
}
}.start();
return null;
}
//从图片url获取图片drawable对象
public static Drawable loadImageFromUrl(String url) {
URL m;
InputStream i = null;
try {
m = new URL(url);
i = (InputStream) m.getContent();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
}
注意这里使用了 SoftReference来缓存图片,允许 GC在需要的时候可以对缓存中的图片进行清理。
异步加载图片类AsyncImageLoader的实现方式
1,在自定义的adapter中调用 loadDrawable(ImageUrl, imageCallback),传入图片的网络地址和一个实现ImageCallback行为的对象(一个匿名实现的 ImageCallback接口的对象)
2,如果图片(通过imageUrl这个key值来判断)在缓存imageCache中不存在的话,图片将从单一(异步)的线程中下载并在下载结束时Drawable返回为null并通过 ImageCallback回调在 ImageAndTextListAdapter类中实现的 imageLoaded方法
3,如果图片确实存在于缓存中,就会马上返回drawable给adapter类的cachedImage,不会回调 ImageCallback
注:HashMap<String, SoftReference<Drawable>>(); 和平常常用的HashMap<key,value>是一样的
注:关于软引用:在Java中内存管理,引用分为四大类,强引用HardReference、弱引用WeakReference、软引用SoftReference和虚引用PhantomReference。它们的区别也很明显,HardReference对象是即使虚拟机内存吃紧抛出OOM也不会导致这一引用的对象被回收,而WeakReference等更适合于一些数量不多,但体积稍微庞大的对象,在这四个引用中,它是最容易被垃圾回收的,而我们对于显示类似Android Market中每个应用的App Icon时可以考虑使用SoftReference来解决内存不至于快速回收,同时当内存短缺面临Java VM崩溃抛出OOM前时,软引用将会强制回收内存,最后的虚引用一般没有实际意义,仅仅观察GC的活动状态,对于测试比较实用同时必须和ReferenceQueue一起使用。对于一组数据,我们可以通过HashMap的方式来添加一组SoftReference对象来临时保留一些数据,同时对于需要反复通过网络获取的不经常改变的内容,可以通过本地的文件系统或数据库来存储缓存。
几个辅助类文件:
图片和文字的实体类
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;
}
}
view的缓存类
package cn.wangmeng.test;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
public class ViewCache {
private View baseView;
private TextView textView;
private ImageView imageView;
public ViewCache(View baseView) {
this.baseView = baseView;
}
public TextView getTextView() {
if (textView == null) {
textView = (TextView) baseView.findViewById(R.id.text);
}
return textView;
}
public ImageView getImageView() {
if (imageView == null) {
imageView = (ImageView) baseView.findViewById(R.id.image);
}
return imageView;
}
}
自定义adapter类
package cn.wangmeng.test;
import java.util.List;
import cn.wangmeng.test.AsyncImageLoader.ImageCallback;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {
private ListView listView;
private AsyncImageLoader asyncImageLoader;
public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {
super(activity, 0, imageAndTexts);
this.listView = listView;
asyncImageLoader = new AsyncImageLoader();
}
public View getView(int position, View convertView, ViewGroup parent) {
Activity activity = (Activity) getContext();
// Inflate the views from XML
View rowView = convertView;
ViewCache viewCache;
if (rowView == null) {
LayoutInflater inflater = activity.getLayoutInflater();
rowView = inflater.inflate(R.layout.image_and_text_row, null);
viewCache = new ViewCache(rowView);
rowView.setTag(viewCache);
} else {
viewCache = (ViewCache) rowView.getTag();
}
ImageAndText imageAndText = getItem(position);
// Load the image and set it on the ImageView
String imageUrl = imageAndText.getImageUrl();
ImageView imageView = viewCache.getImageView();
imageView.setTag(imageUrl);
Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);
if (imageViewByTag != null) {
imageViewByTag.setImageDrawable(imageDrawable);
}
}
});
if (cachedImage == null) {
imageView.setImageResource(R.drawable.default_image);
}else{
imageView.setImageDrawable(cachedImage);
}
// Set the text on the TextView
TextView textView = viewCache.getTextView();
textView.setText(imageAndText.getText());
return rowView;
}
}
adapter类的一些实现方式
1,imageView.setTag(imageUrl);标记此imageUrl的imageView 待没有此图片回调imageLoaded时 取得对应此imageUrl的ImageView(imageViewByTag)
这样是为了保证在回调函数时,listview去更新自己对应item
2,没有此图片时,异步加载类中的loadDrawable返回null 回调imageLoaded放入图片
3,有此图片时,通过loadDrawable取得drawable给cachedImage,放入图片
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
主activity
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>();
// ImageAndText test=new ImageAndText("http://www.wangmeng.cn/images/logo.gif", "test");
// ImageAndText test1=new ImageAndText("http://www.wangmeng.cn/images/ad/t1.gif", "test1");
// ImageAndText test2=new ImageAndText("http://www.wangmeng.cn/images/ad/t3.gif", "test2");
ImageAndText test=new ImageAndText("http://img3.douban.com/lpic/s11082606.jpg", "test");
ImageAndText test1=new ImageAndText("http://img3.douban.com/lpic/s11181635.jpg", "test1");
ImageAndText test2=new ImageAndText("http://img5.douban.com/lpic/s11169899.jpg", "test2");
ImageAndText test3=new ImageAndText("http://img3.douban.com/lpic/s11192408.jpg", "test");
ImageAndText test4=new ImageAndText("http://img1.douban.com/lpic/s11192434.jpg", "test");
ImageAndText test5=new ImageAndText("http://img5.douban.com/lpic/s10324209.jpg", "test");
ImageAndText test6=new ImageAndText("http://img5.douban.com/lpic/s11181029.jpg", "test");
ImageAndText test7=new ImageAndText("http://img3.douban.com/lpic/s11218427.jpg", "test");
ImageAndText test8=new ImageAndText("http://img3.douban.com/lpic/s11162616.jpg", "test");
ImageAndText test9=new ImageAndText("http://img3.douban.com/lpic/s11082606.jpg", "test");
dataArray.add(test);
dataArray.add(test1);
dataArray.add(test2);
dataArray.add(test3);
dataArray.add(test4);
dataArray.add(test5);
dataArray.add(test6);
dataArray.add(test7);
dataArray.add(test8);
dataArray.add(test9);
ImageAndTextListAdapter adapter=new ImageAndTextListAdapter(this, dataArray, list);
list.setAdapter(adapter);
}
}
自己动手实验吧 没问题 截图也看不出效果 主要总结下异步加载类到底如何运行的
补充:
关于代码中adapter类中的 super(activity, 0, imageAndTexts);
先来看官网的构造方法
Public Constructors | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
ArrayAdapter(
Context context, int textViewResourceId)
Constructor
| |||||||||||
ArrayAdapter(
Context context, int resource, int textViewResourceId)
Constructor
| |||||||||||
ArrayAdapter(
Context context, int textViewResourceId, T[] objects)
Constructor
| |||||||||||
ArrayAdapter(
Context context, int resource, int textViewResourceId, T[] objects)
Constructor
| |||||||||||
ArrayAdapter(
Context context, int textViewResourceId,
List<T> objects)
Constructor
| |||||||||||
ArrayAdapter(
Context context, int resource, int textViewResourceId,
List<T> objects)
Constructor
|