ListView的异步加载图片问题与优化

本文介绍如何使用AsyncTask异步加载网络图片到ListView中,解决图片错位问题,并通过LruCache实现图片缓存机制,同时优化滑动时的UI刷新以减少卡顿。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文通过AyncTask异步加载网络图片

参考:
http://blog.youkuaiyun.com/xiaanming/article/details/9825113

1. ListView异步访问网络图片

1.通过Theard加载

通过Url获得位图

public Bitmap getBitmapFromurl(String urlString) {
    Bitmap bitmap = null;
    BufferedInputStream is = null;

    URLConnection connection;
    try {
        URL url = new URL(urlString);//把一个string转化为Url
        connection = (URLConnection) url.openConnection();//通过url开启一个connection
        is = new BufferedInputStream(connection.getInputStream());
        bitmap = BitmapFactory.decodeStream(is);//将isbuffer流数据转化为bitmap
        is.close();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
    }
    return bitmap;
}

通过Thread异步加载位图

public void showImage(ImageView imageView, final String url) {
 new Thread() {

     @Override
     public void run() {
     super.run();
     Bitmap bitmap = getBitmapFromurl(url);
     Message message = Message.obtain();
     message.obj = bitmap;
     mHandler.sendMessage(message);
     }
     }.start();
}

通过Header处理,在主线程刷新UI

private Handler mHandler = new Handler() {
     @Override
     public void handleMessage(Message msg) {
     super.handleMessage(msg);
         if (mImageView.getTag().equals(url)) {//通过Tag防止图片错位
         mImageView.setImageBitmap((Bitmap) msg.obj);
         }
     }
 };

2.通过AsyncTask加载

public void showImageByAsyncTask(ImageView imageView, String url) {
    Bitmap bitmap = getBitmapFromCache(url);//从缓存中读取位图
    if (bitmap == null) {
        new NewsAsyncTask(url).execute(url);//网络加载图片
        //imageView.setImageResource(R.drawable.ic_launcher);//加载默认图片
    } else {
        imageView.setImageBitmap(bitmap);
    }

}

private class NewsAsyncTask extends AsyncTask<String, Void, Bitmap> {
    private String mUrl;

    public NewsAsyncTask(String url) {
        mUrl = url;
    }

    @Override
    protected Bitmap doInBackground(String... params) {
        mUrl = params[0];
        Bitmap bitmap = getBitmapFromurl(mUrl);
        if (bitmap != null) {
            addBitmapToCache(mUrl, bitmap);//将bitmap添加进缓存
        }
        return bitmap;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        super.onPostExecute(bitmap);
        ImageView imageView = (ImageView) mListView.findViewWithTag(mUrl);
        if (imageView != null && bitmap != null) {
            imageView.setImageBitmap(bitmap);
        }
        mTasks.remove(this);
    }

}

2. ListView异步加载网络图片的问题及其优化

1. 加载网络图片错位问题:

通过文艺方法重写listview的getView方法,因为listview缓存机制的存在,缓存池中始终保持三个Item布局,并在加载下一个时用到前面回收的Item,前面的Item以前加载的布局会在后面布局中先加载,然后通过访问网络重新刷新,因此会有图片错位的问题。

通过为加载的网络图片设置Tag的方式解决。在为Item设置图片是先判断Tag是否正确,正确才进行加载。

2. 图片缓存机制

为了使加载过得图片不再重新加载,引进缓存机制来优化listview,这里使用的是LrucaChe

1. 定义
public LruCache<String, Bitmap> myLruCache;//定义一个LruCache泛型
2. 在构造方法中初始化它
// 获取运行时最大缓存
    int maxMemory = (int) Runtime.getRuntime().maxMemory();
    // 设置LruCache可用的最大缓存
    int cacheSize = maxMemory / 5;
    myLruCache = new LruCache<String, Bitmap>(cacheSize) {

        @Override
        protected int sizeOf(String url, Bitmap bitmap) {
            // 重写此方法用来衡量每张图片的大小,默认返回图片的数量
            return bitmap.getByteCount();
        }

    };
3. 添加图片到缓存中
public void addBitmapToCache(String url, Bitmap bitmap) {
    if (getBitmapFromCache(url) == null) {
        myLruCache.put(url, bitmap);
    }
}
4.从缓存中获取图片
public Bitmap getBitmapFromCache(String url) {
    return myLruCache.get(url);

}

3. 滑动卡顿问题

在滑动时系统不停的加载网络图片然后刷新Item,频繁刷新UI容易使系统卡顿。

在滑动时停止一切数据加载任务,当滑动停止后再次加载当前页的数据

  1. Apater添加OnScrollListener接口
  2. 注册接口
  3. 在onScroll函数中获取当前页的Item的开始项与结束项,并判断如果是第一次启动则手动加载
  4. onScrollStateChanged函数中判断当前状态:滑动状态时停止加载图片线程,停止状态时启动加载图片线程

代码ListAdapter中:

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
    if (scrollState == SCROLL_STATE_TOUCH_SCROLL) {
        // 停止加载图片
        mImageload.cancelload();
    } else if (scrollState == SCROLL_STATE_IDLE) {
        // 开始加载图片
        mImageload.loadImages(mStart, mEnd);
    }
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
        int visibleItemCount, int totalItemCount) {
    mStart = firstVisibleItem;
    mEnd = firstVisibleItem + visibleItemCount;
    if (mFirst && visibleItemCount > 0) {
        mImageload.loadImages(mStart, mEnd);
        mFirst = false;
    }
}

细节处理:
1. 定义String数组用来管理当前页面的URL,在loadImages中初始化它

public void loadImages(int start, int end) {
    for (int i = start; i < end; i++) {
        final String url = ListAdapter.URLS[i];
        Bitmap bitmap = getBitmapFromCache(url);
        if (bitmap == null) {
            NewsAsyncTask task = new NewsAsyncTask(url);
            task.execute(url);
            mTasks.add(task);//将task加入集合,便于管理
        } else {
            ImageView imageView = (ImageView) mListView
                    .findViewWithTag(url);
            imageView.setImageBitmap(bitmap);
        }
    }
}
  1. 定义一个集合,用于管理NewsAyncTask

    private Set mTasks;

  2. 自定义关闭AyncTask函数

    public void cancelload() {
    if (mTasks != null) {
        for (NewsAsyncTask task : mTasks) {
            task.cancel(false);
        }
    }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值