zoukankan      html  css  js  c++  java
  • 【转载】ListView如何加载远程图片

    ListView在Android应用里扮演非常重要的角色,但很多开发者在使用 ListView时都遇到过不少麻烦。一个常见的问题是:列表中要显示一系列记录,每条记录带有一张缩略图(产品照片、用户头像等等),而这个缩略图是通 过一个远程URL地址来标识的。这样的应用场景该如何实现呢?

    为了避免下载图片带来的延迟,所有远程图片都应该使用异步方式加载,即使用单独的线程下载图片,待图片下载完毕后显示在ImageView里。Android里可以像普通Java一样启动新线程,但当这个线程要更新界面时,必须使用Handler来请求,否则会为应用程序带来潜在危害。

    RemoteImageHelper

    为了将复杂的逻辑分离,我们单独写一个名为RemoteImageHelper的类来处理“异步下载图片并更新到界面”这个问题,这个类能够实现以下功能:

    • 图片开始下载前,ImageView里显示一个表示“正在加载”的占位图;
    • 图片在后台下载,下载完成后显示在ImageView里;
    • 若图片下载失败,ImageView显示一个表示下载失败的占位图;

    下面让我们来看一下实现代码:

    首先需要有一个方法下载远程图片,这里我们不用把图片下载到手机上,直接返回一个InputStream类型的结果即可。如果运行时这个方法报错,请检查是否在AndroidManifest.xml里添加了android.permission.INTERNET权限。

    private InputStream download(String urlString) throws MalformedURLException, IOException {
        InputStream inputStream = (InputStream) new URL(urlString).getContent();
        return inputStream;
    }

    然后是最主要的异步加载图片方法,“正在下载”和“下载失败”的图片可根据需要自己替换。代码如下所示:

    private final Map<String, Drawable> cache = new HashMap<String, Drawable>();
    
    public void loadImage(final ImageView imageView, final String urlString, boolean useCache) {
        if (useCache && cache.containsKey(urlString)) {
            imageView.setImageDrawable(cache.get(urlString));
        }
    
        //Show a "Loading" image here
        imageView.setImageResource(R.drawable.image_indicator);
    
        Log.d(this.getClass().getSimpleName(), "Image url:" + urlString);
    
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageView.setImageDrawable((Drawable) message.obj);
            }
        };
    
        Runnable runnable = new Runnable() {
            public void run() {
                Drawable drawable = null;
                try {
                    InputStream is = download(urlString);
                    drawable = Drawable.createFromStream(is, "src");
    
                    if (drawable != null) {
                        cache.put(urlString, drawable);
                    }
                } catch (Exception e) {
                    Log.e(this.getClass().getSimpleName(), "Image download failed", e);
                    //Show a "download fail" image 
                    drawable = imageView.getResources().getDrawable(R.drawable.image_fail);
                }
                
                //Notify UI thread to show this image using Handler
                Message msg = handler.obtainMessage(1, drawable);
                handler.sendMessage(msg);
            }
        };
        new Thread(runnable).start();
    }

    关于缓存:在这个例子里我们使用一个内存中的HashMap作为图片缓存,它实现简单但当应用退出后缓存就会被清除。在实际项目里,你可以考虑实现一个基于文件的缓存机制,即将下载的图片保存到SD卡上,注意要定期清除长期不用的图片以节约存储空间。

    使用RemoteImageHelper

    如何使用这个类呢?下面是一个例子。请注意,为了达到更好的演示效果,代码里在调用loadImage()方法时第三个参数用false禁止了图片缓存功能,在实际项目中,你很可能需要改为true来避免重复下载图片以便提高性能。

    List<MyRecord> exampleRecords;
    LazyImageHelper lazyImageHelper = new LazyImageHelper();
    
    class MyAdapter extends ArrayAdapter<MyRecord> {
    
        public MyAdapter(Context context) {
            super(context, R.layout.record_row, R.id.lblLabel, exampleRecords);
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = super.getView(position, convertView, parent);
            MyRecord record = getItem(position);
    
            TextView lblLabel = (TextView) view.findViewById(R.id.lblLabel);
            ImageView imageView = (ImageView) view.findViewById(R.id.img);
    
            lblLabel.setText(record.getLabel());
    
            //For demo purpose, cache is DISABLED here.
            lazyImageHelper.loadImage(imageView, record.getImageUrl(), false);
    
            //To enable cache, simply use following code:
            //lazyImageHelper.loadImage(imageView, record.getImageUrl(), true);
    
            return view;
        }
    }

    以上代码中的MyRecord是一个简单的POJO类,表示一个业务对象,它具有id、label和imageUrl三个属性。你可以在完整的工程代码中找到它。

    代码下载

    上述示例工程编译后的APK文件点击这里下载,可运行在Android 2.1或以上版本。

    上述示例工程的源代码点击这里下载。

    参考资料

    Handler

    android的消息处理机制

    How do I do a lazy load of images in ListView

    Issue 13959:Make listviews more programmer friendly

    原文地址:http://www.cnblogs.com/bjzhanghao/archive/2012/11/11/load-images-in-android-listview.html

  • 相关阅读:
    玩转MySQL之Linux下的简单操作(服务启动与关闭、启动与关闭、查看版本)
    玩转MySQL之Linux下修改默认编码
    机器学习算法及应用领域相关的中国大牛
    [转载]Python 包管理工具解惑
    Vim常用操作和快捷键技巧总结
    [转载]那些C++牛人的博客
    [转载]学习c/c++的好网站
    [转载]C++内存管理
    [转载]SQL数据库如何加快查询速度
    [转载]Python3.x和Python2.x的区别
  • 原文地址:https://www.cnblogs.com/fengzhblog/p/2770722.html
Copyright © 2011-2022 走看看