`
king_tt
  • 浏览: 2117701 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Android 如何在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

分享到:
评论

相关推荐

    android异步远程解析json数据绑定到listview上

    android异步远程解析json数据绑定到ListView上,响应地址也有了,分层思想写的,要是有什么异常之类的可以Q我

    Android40个经典源码

    15 Android远程登录含有loading登录效果~~完整代码和超级详细注释 16 AsyncTask进度条加载网站数据到ListView 17 EditText插入QQ表情源码 18 OpenGL的一个简单的例子 19闹钟 20 指南针 21 重力感应 22 android 查询...

    android开发资料大全

    Android瀑布流加载图片效果实例 Android中利用ViewPager实现视图切换 Android泡泡聊天界面的源码实现 android 实现EditText震动效果 Touch Index Bar (有锤子有真相) Android数据库最基础的一个例子(本人已测试...

    Andorid项目源码(153套)

    Android模仿易网新闻页面源码(异步加载).zip Android瀑布流实现,类似于蘑菇街和迷尚 应用里的排列.zip android面试题.zip Android任务管理器源码.zip Android奇艺高清UI界面源代码.zip android网络视频播放器(完整...

    Google Android SDK开发范例大全(PDF高清完整版1)(4-1)

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google Android SDK开发范例大全(PDF完整版4)(4-4)

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google Android SDK开发范例大全(PDF高清完整版3)(4-3)

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google Android SDK开发范例大全的目录

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google Android SDK开发范例大全(完整版附部分源码).pdf

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——...

    精通ANDROID 3(中文版)1/2

    23.5.1 在Android搜索中使用操作键  23.5.2 使用应用程序特定的搜索上下文  23.6 资源  23.7 对平板电脑的意义  23.8 小结  第24章 文本到语音转换  24.1 Android中的文本到语音转换  24.2 使用语段...

    Android典型技术模块开发详解

    6.3.3 实现远程控制计数器示例 6.4 AIDL深入练习 6.4.1 服务端实现 6.4.2 客户端实现 6.5 系统服务 6.5.1 获得系统服务 6.5.2 获取屏幕分辨率 6.5.3 剪贴板服务 6.5.4 电话服务 6.5.5 定时提醒服务 6.5.6 音频服务 ...

    Google Android SDK 开发范例大全01

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google Android SDK 开发范例大全02

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google+Android+SDK开发范例大全

    4.22 加载手机磁盘里的图文件——使用decodeFile方法 4.23 动态放大缩小ImageView里的图片——运用Matrix对象来缩放图文件 4.24 动态旋转图片——Bitmap与Matrix旋转ImageView 4.25 猜猜我在想什么——...

    Google Android sdk 开发范例大全 部分章节代码

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    Google Android SDK开发范例大全(完整版)

    4.19 在Activity里显示列表列表——ListView的布局 4.20 以动态列表配置选项——ListActivity与Menu整合技巧 4.21 查找程序根目录下所有文件——JavaI/O与ListActivity的结合.. 4.22 加载手机磁盘里的图文件——使用...

    精通Android 3 (中文版)2/2

    23.5.1 在Android搜索中使用操作键  23.5.2 使用应用程序特定的搜索上下文  23.6 资源  23.7 对平板电脑的意义  23.8 小结  第24章 文本到语音转换  24.1 Android中的文本到语音转换  24.2 使用语段...

Global site tag (gtag.js) - Google Analytics