天天看点

android listview动态加载网络图片不显示,Android ListView异步加载图片方法详解

本文实例讲述了Android ListView异步加载图片方法。分享给大家供大家参考,具体如下:

先说说这篇文章的优点把,开启线程异步加载图片,然后刷新UI显示图片,而且通过弱引用缓存网络加载的图片,节省了再次连接网络的开销。

这样做无疑是非常可取的方法,但是加载图片时仍然会感觉到轻微的卡屏现象,特别是listview里的item在进行快速滑动的时候。

我找了一下原因,可能是在listview快速滑动屏幕的时候划过的item太多 而且每次调用getView方法后就会异步的在过去某个时间内用handler刷新一下UI,

如果在同一时间调用handler刷新UI次数多了就会造成这样的卡屏现象。

后来又一想,其实我们完全没有必要在listview正在滑动的时候去后台加载图片(不管这是图片是在缓存里还是在网络上),这样无疑造成了很大的资源浪费。

我们只需要在listview滑动停止之后再去加载listview里面显示的几个item里面的图片就好了。

根据以上想法,我做了一些设计改造:

1.在adapter 的 getview方法里面启动加载图片的thread,如果listview在滑动则wait

2.监听listview滑动停止事件,获得listview显示的item的最上面和最下面的序号,并唤醒所有加载图片的thread,判断加载图片的序号是否是在范围内,如果是则继续加载,如果不是则结束thread

部分代码如下:

@Override

public View getView(int position, View convertView, ViewGroup parent)

{

if(convertView == null){

convertView = mInflater.inflate(R.layout.book_item_adapter, null);

}

BookModel model = mModels.get(position);

convertView.setTag(position);

ImageView iv = (ImageView) convertView.findViewById(R.id.sItemIcon);

TextView sItemTitle = (TextView) convertView.findViewById(R.id.sItemTitle);

TextView sItemInfo = (TextView) convertView.findViewById(R.id.sItemInfo);

sItemTitle.setText(model.book_name);

sItemInfo.setText(model.out_book_url);

iv.setBackgroundResource(R.drawable.rc_item_bg);

syncImageLoader.loadImage(position,model.out_book_pic,imageLoadListener);

return convertView;

}

SyncImageLoader.OnImageLoadListener imageLoadListener = new SyncImageLoader.OnImageLoadListener(){

@Override

public void onImageLoad(Integer t, Drawable drawable) {

//BookModel model = (BookModel) getItem(t);

View view = mListView.findViewWithTag(t);

if(view != null){

ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);

iv.setBackgroundDrawable(drawable);

}

}

@Override

public void onError(Integer t) {

BookModel model = (BookModel) getItem(t);

View view = mListView.findViewWithTag(model);

if(view != null){

ImageView iv = (ImageView) view.findViewById(R.id.sItemIcon);

iv.setBackgroundResource(R.drawable.rc_item_bg);

}

}

};

public void loadImage(){

int start = mListView.getFirstVisiblePosition();

int end =mListView.getLastVisiblePosition();

if(end >= getCount()){

end = getCount() -1;

}

syncImageLoader.setLoadLimit(start, end);

syncImageLoader.unlock();

}

AbsListView.OnScrollListener onScrollListener = new AbsListView.OnScrollListener() {

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

switch (scrollState) {

case AbsListView.OnScrollListener.SCROLL_STATE_FLING:

DebugUtil.debug("SCROLL_STATE_FLING");

syncImageLoader.lock();

break;

case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:

DebugUtil.debug("SCROLL_STATE_IDLE");

loadImage();

//loadImage();

break;

case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:

syncImageLoader.lock();

break;

default:

break;

}

}

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

// TODO Auto-generated method stub

}

};

package cindy.android.test.synclistview;

import java.io.DataInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.lang.ref.SoftReference;

import java.net.URL;

import java.util.HashMap;

import android.graphics.drawable.Drawable;

import android.os.Environment;

import android.os.Handler;

public class SyncImageLoader {

private Object lock = new Object();

private boolean mAllowLoad = true;

private boolean firstLoad = true;

private int mStartLoadLimit = 0;

private int mStopLoadLimit = 0;

final Handler handler = new Handler();

private HashMap> imageCache = new HashMap>();

public interface OnImageLoadListener {

public void onImageLoad(Integer t, Drawable drawable);

public void onError(Integer t);

}

public void setLoadLimit(int startLoadLimit,int stopLoadLimit){

if(startLoadLimit > stopLoadLimit){

return;

}

mStartLoadLimit = startLoadLimit;

mStopLoadLimit = stopLoadLimit;

}

public void restore(){

mAllowLoad = true;

firstLoad = true;

}

public void lock(){

mAllowLoad = false;

firstLoad = false;

}

public void unlock(){

mAllowLoad = true;

synchronized (lock) {

lock.notifyAll();

}

}

public void loadImage(Integer t, String imageUrl,

OnImageLoadListener listener) {

final OnImageLoadListener mListener = listener;

final String mImageUrl = imageUrl;

final Integer mt = t;

new Thread(new Runnable() {

@Override

public void run() {

if(!mAllowLoad){

DebugUtil.debug("prepare to load");

synchronized (lock) {

try {

lock.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

if(mAllowLoad && firstLoad){

loadImage(mImageUrl, mt, mListener);

}

if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){

loadImage(mImageUrl, mt, mListener);

}

}

}).start();

}

private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener){

if (imageCache.containsKey(mImageUrl)) {

SoftReference softReference = imageCache.get(mImageUrl);

final Drawable d = softReference.get();

if (d != null) {

handler.post(new Runnable() {

@Override

public void run() {

if(mAllowLoad){

mListener.onImageLoad(mt, d);

}

}

});

return;

}

}

try {

final Drawable d = loadImageFromUrl(mImageUrl);

if(d != null){

imageCache.put(mImageUrl, new SoftReference(d));

}

handler.post(new Runnable() {

@Override

public void run() {

if(mAllowLoad){

mListener.onImageLoad(mt, d);

}

}

});

} catch (IOException e) {

handler.post(new Runnable() {

@Override

public void run() {

mListener.onError(mt);

}

});

e.printStackTrace();

}

}

public static Drawable loadImageFromUrl(String url) throws IOException {

DebugUtil.debug(url);

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){

File f = new File(Environment.getExternalStorageDirectory()+"/TestSyncListView/"+MD5.getMD5(url));

if(f.exists()){

FileInputStream fis = new FileInputStream(f);

Drawable d = Drawable.createFromStream(fis, "src");

return d;

}

URL m = new URL(url);

InputStream i = (InputStream) m.getContent();

DataInputStream in = new DataInputStream(i);

FileOutputStream out = new FileOutputStream(f);

byte[] buffer = new byte[1024];

int byteread=0;

while ((byteread = in.read(buffer)) != -1) {

out.write(buffer, 0, byteread);

}

in.close();

out.close();

Drawable d = Drawable.createFromStream(i, "src");

return loadImageFromUrl(url);

}else{

URL m = new URL(url);

InputStream i = (InputStream) m.getContent();

Drawable d = Drawable.createFromStream(i, "src");

return d;

}

}

}

除了本身已有的弱引用缓存图片,我还添加了本地SD卡缓存图片(这两种缓存方法各有好处,如果图片经常变化建议内存缓存图片,如果是不经常修改的图片建议SD卡缓存)

希望本文所述对大家Android程序设计有所帮助。