Android之ListView优化(使用Lrucache,图片滑动时使用默认图片,停止时加载)

本文介绍了一种利用LRUCache进行图片缓存的方法,适用于移动开发中ListView滚动时图片的异步加载,通过自定义线程处理图片加载任务,确保在内存有限的情况下高效加载图片。

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

注意:LruCache是有版本限制的,低版本的sdk需要在libs文件夹添加相应的support-4v文件。
本文改造的大部分是参考http://www.iteye.com/topic/1118828,感谢。
不废话直接上工程代码,内有关键注释,项目就不上传了,自己对照着上面网址改呗。


首先是Application文件,负责创建图片存储文件夹:

复制代码
public class MyApp extends Application{
    @Override
    public void onCreate() {
        super.onCreate();
        File f = new File(Environment.getExternalStorageDirectory()+"/TestSyncListView/pic/");
        if (!f.exists()) {
            f.mkdirs();
        }
    }
}
复制代码


图像读取工具类:

?
public class SyncImageLoaderUtil {
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<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
private LruCache<String,Bitmap> mMemoryCache;
RunInOtherThread runInOutherThread;
public SyncImageLoaderUtil(Context context) {
super ();
int memClass = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
int cacheSize = 1024 * 1024 *memClass / 8 ;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize){
@Override
protected int sizeOf(String key, Bitmap value) {
// TODO Auto-generated method stub
return value.getRowBytes();
}
};
runInOutherThread = new RunInOtherThread();
runInOutherThread.start();
}
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) {
// LogUtil.i("test", 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;
runInOutherThread.getHandler().post( new Runnable() {
@Override
public void run() {
if (!mAllowLoad) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
if (mAllowLoad && firstLoad) {
loadImage(mImageUrl, mt, mListener);
}
// LogUtil.e("test", "原始开始:"+mStartLoadLimit+"原始当前位置:"+mt+"原始结束:"+mStopLoadLimit);
if (mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit) {
// LogUtil.e("test", "开始:"+mStartLoadLimit+"当前位置:"+mt+"结束:"+mStopLoadLimit);
loadImage(mImageUrl, mt, mListener);
}
}
});
}
private void loadImage( final String mImageUrl, final Integer mt,
final OnImageLoadListener mListener) {
if (mImageUrl!= null && mMemoryCache.get(mImageUrl)!= null ) {
// SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
final Drawable d = new BitmapDrawable(mMemoryCache.get(mImageUrl));
// LogUtil.d("ppp", "drawable:"+d);
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 ) {
mMemoryCache.put(mImageUrl, ((BitmapDrawable)d).getBitmap());
}
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()
+ "/Weiyu/pic/" + MD5Util.getMD5(url.getBytes()));
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();
return loadImageFromUrl(url);
} else {
URL m = new URL(url);
InputStream i = (InputStream) m.getContent();
Drawable d = Drawable.createFromStream(i, "src" );
return d;
}
}
}

  
线程辅助类:

?
public class RunInOtherThread {
private static final String LOG_TAG = "RunInOtherThread" ;
private LooperThread localThread = new LooperThread();
private boolean isRunning = true ;
public Handler getHandler(){
return localThread.getHandler();
}
private class LooperThread extends Thread {
private Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
onReceiveMessage(msg.what);
}
};
Looper.loop();
}
Handler getHandler(){
return mHandler;
}
}
public void start(){
localThread.start();
}
public void quit(){
localThread.getHandler().getLooper().quit();
}
public void sendMessage( int what){
getHandler().sendEmptyMessage(what);
}
public Thread getThread(){
return localThread;
}
public void onReceiveMessage( int what){};
}

  
使用类:

?
// 实例化工具类
SyncImageLoaderUtil syncImageLoader = new SyncImageLoaderUtil(mContext);
syncImageLoader.loadImage(position, model.mPic, imageLoadListener); //应用接口:参数一是加载图片的位置;参数二是加载的ImageView;参数三是回调接口
// map保存的键是位置,值是listview对应位置的布局
HashMap map = new HashMap();
map.put(position, convertView);
SyncImageLoaderUtil.OnImageLoadListener imageLoadListener = new SyncImageLoaderUtil.OnImageLoadListener() {
@Override
public void onImageLoad(Integer t, Drawable drawable) {
View view = (View) map.get(t);
if (view != null ) {
ImageView iv = (ImageView) view.findViewById(R.id.image);
iv.setBackgroundDrawable(drawable);
}
}
@Override
public void onError(Integer t) {
// 图片加载失败
// 取得listview对应的位置的行的内容布局
MusicModel model = (MusicModel) getItem(t);
View view = mListView.findViewWithTag(model);
if (view != null ) {
ImageView iv = (ImageView) view.findViewById(R.id.image);
iv.setBackgroundResource(R.drawable.img_pic);
}
}
};
// 实现类而且需要实现OnScrollListener接口
public void loadImage() {
// 不要在这里使用listview的getFirstVisiblePosition方法,位置不准
if (end >= getCount()) {
end = getCount() - 1 ;
}
syncImageLoader.setLoadLimit(start, end);
syncImageLoader.unlock();
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
if (lodingView) {
switch (scrollState) {
case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
syncImageLoader.lock();
break ;
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
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) {
// 在这里取得的位置较准确,不过也会出现特殊的奇疤机型是不行的
// start与end是定义的变量
start = firstVisibleItem;
end = firstVisibleItem + visibleItemCount;
if (firstVisibleItem != 0 ) {
// lodingView是控制变量,用来控制第一次进来视图加载读取图片
lodingView = true ;
} else {
lodingView = false ;
loadImage();
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值