list多线程实现异步加载

ListView 是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的

所以这里就需要把这些信息利用多线程实现异步加载

实现这样功能的类

view plaincopy to clipboardprint?
01.public class AsyncImageLoader {  
02.    private HashMap<String, SoftReference<Drawable>> imageCache;  
03.   
04.    public AsyncImageLoader() {  
05.        imageCache = new HashMap<String, SoftReference<Drawable>>();  
06.    }  
07.   
08.    public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {  
09.        if (imageCache.containsKey(imageUrl)) {  
10.            SoftReference<Drawable> softReference = imageCache.get(imageUrl);  
11.            Drawable drawable = softReference.get();  
12.            if (drawable != null) {  
13.                return drawable;  
14.            }  
15.        }  
16.        final Handler handler = new Handler() {  
17.            @Override 
18.            public void handleMessage(Message message) {  
19.                imageCallback.imageLoaded((Drawable) message.obj, imageUrl);  
20.            }  
21.        };  
22.        new Thread() {  
23.            @Override 
24.            public void run() {  
25.                Drawable drawable = loadImageFromUrl(imageUrl);  
26.                imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));  
27.                Message message = handler.obtainMessage(0, drawable);  
28.                handler.sendMessage(message);  
29.            }  
30.        }.start();  
31.        return null;  
32.    }  
33.   
34.    public static Drawable loadImageFromUrl(String url) {  
35.        // ...  
36.    }  
37.   
38.    public interface ImageCallback {  
39.        public void imageLoaded(Drawable imageDrawable, String imageUrl);  
40.    }  
41.} 
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() {
            @Override
            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));
                Message message = handler.obtainMessage(0, drawable);
                handler.sendMessage(message);
            }
        }.start();
        return null;
    }
 
    public static Drawable loadImageFromUrl(String url) {
        // ...
    }
 
    public interface ImageCallback {
        public void imageLoaded(Drawable imageDrawable, String imageUrl);
    }
}
 

注意这里使用了 SoftReference来缓存图片,允许 GC在需要的时候可以对缓存中的图片进行清理。它这样工作:

·         调用 loadDrawable(ImageUrl, imageCallback),传入一个匿名实现的 ImageCallback接口

·         如果图片在缓存中不存在的话,图片将从单一的线程中下载并在下载结束时通过 ImageCallback回调

·         如果图片确实存在于缓存中,就会马上返回,不会回调 ImageCallback

        然后我们还可以根据09google I/0开发者大会提到的方式来继续优化Adapter 使用ViewHolder来减少一些比较费时的操作,譬如inflate XML 和 findViewById()等操作

      
view plaincopy to clipboardprint?
01.public class ImageAndTextListAdapter extends ArrayAdapter<ImageAndText> {  
02.   
03.    private ListView listView;  
04.    private AsyncImageLoader asyncImageLoader;  
05.   
06.    public ImageAndTextListAdapter(Activity activity, List<ImageAndText> imageAndTexts, ListView listView) {  
07.        super(activity, 0, imageAndTexts);  
08.        this.listView = listView;  
09.        asyncImageLoader = new AsyncImageLoader();  
10.    }  
11.   
12.    @Override 
13.    public View getView(int position, View convertView, ViewGroup parent) {  
14.        Activity activity = (Activity) getContext();  
15.   
16.        // Inflate the views from XML  
17.        View rowView = convertView;  
18.        ViewCache viewCache;  
19.        if (rowView == null) {  
20.            LayoutInflater inflater = activity.getLayoutInflater();  
21.            rowView = inflater.inflate(R.layout.image_and_text_row, null);  
22.            viewCache = new ViewCache(rowView);  
23.            rowView.setTag(viewCache);  
24.        } else {  
25.            viewCache = (ViewCache) rowView.getTag();  
26.        }  
27.        ImageAndText imageAndText = getItem(position);  
28.   
29.        // Load the image and set it on the ImageView  
30.        String imageUrl = imageAndText.getImageUrl();  
31.        ImageView imageView = viewCache.getImageView();  
32.        imageView.setTag(imageUrl);  
33.        Drawable cachedImage = asyncImageLoader.loadDrawable(imageUrl, new ImageCallback() {  
34.            public void imageLoaded(Drawable imageDrawable, String imageUrl) {  
35.                ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);  
36.                if (imageViewByTag != null) {  
37.                    imageViewByTag.setImageDrawable(imageDrawable);  
38.                }  
39.            }  
40.        });  
41.        imageView.setImageDrawable(cachedImage);  
42.   
43.        // Set the text on the TextView  
44.        TextView textView = viewCache.getTextView();  
45.        textView.setText(imageAndText.getText());  
46.   
47.        return rowView;  
48.    }  
49.}  
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();
    }
 
    @Override
    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);
                }
            }
        });
        imageView.setImageDrawable(cachedImage);
 
        // Set the text on the TextView
        TextView textView = viewCache.getTextView();
        textView.setText(imageAndText.getText());
 
        return rowView;
    }

      这里我们没有加载完iamge之后直接设定到相应的ImageView上 ,而是通过Tag查找,这里我们重用的View 这里有个listView的引用来通过Tag查找 可见 CallBack的实现

     
view plaincopy to clipboardprint?
01.ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);  
02.               if (imageViewByTag != null) {  
03.                   imageViewByTag.setImageDrawable(imageDrawable);  
04.               } 
 ImageView imageViewByTag = (ImageView) listView.findViewWithTag(imageUrl);
                if (imageViewByTag != null) {
                    imageViewByTag.setImageDrawable(imageDrawable);
                }

      这里通过ViewCatch来减少了 findViewById的使用

    
view plaincopy to clipboardprint?
01.public class ViewCache {  
02.   
03.    private View baseView;  
04.    private TextView textView;  
05.    private ImageView imageView;  
06.   
07.    public ViewCache(View baseView) {  
08.        this.baseView = baseView;  
09.    }  
10.   
11.    public TextView getTextView() {  
12.        if (textView == null) {  
13.            textView = (TextView) baseView.findViewById(R.id.text);  
14.        }  
15.        return titleView;  
16.    }  
17.   
18.    public ImageView getImageView() {  
19.        if (imageView == null) {  
20.            imageView = (ImageView) baseView.findViewById(R.id.image);  
21.        }  
22.        return imageView;  
23.    }  
24.}  
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 titleView;
    }
 
    public ImageView getImageView() {
        if (imageView == null) {
            imageView = (ImageView) baseView.findViewById(R.id.image);
        }
        return imageView;
    }

     总结 :这里主要做了三点优化

•在单一线程里加载图片
•  重用列表中行
•缓存行中的 View


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wanglong0537/archive/2011/04/19/6334005.aspx

原文地址:https://www.cnblogs.com/moonvan/p/2024957.html