注意: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 LooperThreadextends 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();
}
}