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