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