http://www.iteye.com/topic/1118828

http://www.iteye.com/topic/1127914

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

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

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

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

    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;

Syncimageloader代码

  1. import java.io.DataInputStream;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.lang.ref.SoftReference;
  8. import java.net.URL;
  9. import java.util.HashMap;
  10. import android.graphics.drawable.Drawable;
  11. import android.os.Environment;
  12. import android.os.Handler;
  13. public class SyncImageLoader {
  14. private Object lock = new Object();
  15. private boolean mAllowLoad = true;
  16. private boolean firstLoad = true;
  17. private int mStartLoadLimit = 0;
  18. private int mStopLoadLimit = 0;
  19. final Handler handler = new Handler();
  20. private HashMap<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>();
  21. public interface OnImageLoadListener {
  22. public void onImageLoad(Integer t, Drawable drawable);
  23. public void onError(Integer t);
  24. }
  25. public void setLoadLimit(int startLoadLimit,int stopLoadLimit){
  26. if(startLoadLimit > stopLoadLimit){
  27. return;
  28. }
  29. mStartLoadLimit = startLoadLimit;
  30. mStopLoadLimit = stopLoadLimit;
  31. }
  32. public void restore(){
  33. mAllowLoad = true;
  34. firstLoad = true;
  35. }
  36. public void lock(){
  37. mAllowLoad = false;
  38. firstLoad = false;
  39. }
  40. public void unlock(){
  41. mAllowLoad = true;
  42. synchronized (lock) {
  43. lock.notifyAll();
  44. }
  45. }
  46. public void loadImage(Integer t, String imageUrl,
  47. OnImageLoadListener listener) {
  48. final OnImageLoadListener mListener = listener;
  49. final String mImageUrl = imageUrl;
  50. final Integer mt = t;
  51. new Thread(new Runnable() {
  52. @Override
  53. public void run() {
  54. if(!mAllowLoad){
  55. DebugUtil.debug("prepare to load");
  56. synchronized (lock) {
  57. try {
  58. lock.wait();
  59. } catch (InterruptedException e) {
  60. // TODO Auto-generated catch block
  61. e.printStackTrace();
  62. }
  63. }
  64. }
  65. if(mAllowLoad && firstLoad){
  66. loadImage(mImageUrl, mt, mListener);
  67. }
  68. if(mAllowLoad && mt <= mStopLoadLimit && mt >= mStartLoadLimit){
  69. loadImage(mImageUrl, mt, mListener);
  70. }
  71. }
  72. }).start();
  73. }
  74. private void loadImage(final String mImageUrl,final Integer mt,final OnImageLoadListener mListener){
  75. if (imageCache.containsKey(mImageUrl)) {
  76. SoftReference<Drawable> softReference = imageCache.get(mImageUrl);
  77. final Drawable d = softReference.get();
  78. if (d != null) {
  79. handler.post(new Runnable() {
  80. @Override
  81. public void run() {
  82. if(mAllowLoad){
  83. mListener.onImageLoad(mt, d);
  84. }
  85. }
  86. });
  87. return;
  88. }
  89. }
  90. try {
  91. final Drawable d = loadImageFromUrl(mImageUrl);
  92. if(d != null){
  93. imageCache.put(mImageUrl, new SoftReference<Drawable>(d));
  94. }
  95. handler.post(new Runnable() {
  96. @Override
  97. public void run() {
  98. if(mAllowLoad){
  99. mListener.onImageLoad(mt, d);
  100. }
  101. }
  102. });
  103. } catch (IOException e) {
  104. handler.post(new Runnable() {
  105. @Override
  106. public void run() {
  107. mListener.onError(mt);
  108. }
  109. });
  110. e.printStackTrace();
  111. }
  112. }
  113. public static Drawable loadImageFromUrl(String url) throws IOException {
  114. DebugUtil.debug(url);
  115. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  116. File f = new File(Environment.getExternalStorageDirectory()+"/TestSyncListView/"+MD5.getMD5(url));
  117. if(f.exists()){
  118. FileInputStream fis = new FileInputStream(f);
  119. Drawable d = Drawable.createFromStream(fis, "src");
  120. return d;
  121. }
  122. URL m = new URL(url);
  123. InputStream i = (InputStream) m.getContent();
  124. DataInputStream in = new DataInputStream(i);
  125. FileOutputStream out = new FileOutputStream(f);
  126. byte[] buffer = new byte[1024];
  127. int   byteread=0;
  128. while ((byteread = in.read(buffer)) != -1) {
  129. out.write(buffer, 0, byteread);
  130. }
  131. in.close();
  132. out.close();
  133. Drawable d = Drawable.createFromStream(i, "src");
  134. return loadImageFromUrl(url);
  135. }else{
  136. URL m = new URL(url);
  137. InputStream i = (InputStream) m.getContent();
  138. Drawable d = Drawable.createFromStream(i, "src");
  139. return d;
  140. }
  141. }
  142. }

TestSyncListView.rar (147.8
KB)

其实改动不大,就是把之前的new Thread改成了 Handler Looper Thread的模式,这样在第一次滑动的时候就进入了wait状态,又因为handler里面的runnable是队列执行的,所以handler一直在添加的runnable也在等待,这样就避免了多次new
thread的问题,从头到尾就只有一个thread,别的不多说,看修改后的代码。
Runinotherthread代码

    import android.os.Handler;
import android.os.Looper;
import android.os.Message; 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){}; } Syncimageloader代码 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 cindy.android.debug.DebugUtil; 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<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); RunInOtherThread runInOutherThread; public SyncImageLoader() {
super();
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) {
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 {
DebugUtil.debug("wait start.....");
lock.wait();
DebugUtil.debug("wait end.....");
} 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);
}
} });
} private void loadImage(final String mImageUrl, final Integer mt,
final OnImageLoadListener mListener) { if (imageCache.containsKey(mImageUrl)) {
SoftReference<Drawable> 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<Drawable>(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;
} }
}

转:Android ListView 异步加载图片的更多相关文章

  1. 又优化了一下 Android ListView 异步加载图片

    写这篇文章并不是教大家怎么样用listview异步加载图片,因为这样的文章在网上已经有很多了,比如这位仁兄写的就很好: http://www.iteye.com/topic/685986 我也是因为看 ...

  2. android listview 异步加载图片并防止错位

    网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertVie ...

  3. android ListView异步加载图片(双缓存)

    首先声明,参考博客地址:http://www.iteye.com/topic/685986 对于ListView,相信很多人都很熟悉,因为确实太常见了,所以,做的用户体验更好,就成了我们的追求... ...

  4. Android的ListView异步加载图片时,错位、重复、闪烁问题的分析及解决方法

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图 ...

  5. listview异步加载图片并防止错位

    android listview 异步加载图片并防止错位 网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 conver ...

  6. Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

    我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如L ...

  7. Android 实现ListView异步加载图片

    ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; ...

  8. ListView异步加载图片,完美实现图文混排

    昨天参加一个面试,面试官让当场写一个类似于新闻列表的页面,文本数据和图片都从网络上获取,想起我还没写过ListView异步加载图片并实现图文混排效果的文章,so,今天就来写一下,介绍一下经验. Lis ...

  9. ListView异步加载图片

    ListView异步加载图片是非常实用的方法,凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; ...

随机推荐

  1. 笔记-flask基础操作

    笔记-flask基础操作 1.      前言 本文为flask基础学习及操作笔记,主要内容为flask基础操作及相关代码. 2.      开发环境配置 2.1.    编译环境准备 安装相关Lib ...

  2. Fragment Touch事件泄露

    当Fragment的栈里面有几个fragment的时候,这个时候如果是几个fragment状态是hide,当你触摸当前fragment的时候,下层的fragment的事件被触发,这是由于Touch事件 ...

  3. Android面试收集录4 Fragment详解

    1.什么是Fragment? 你可以简单的理解为,Fragment是显示在Activity中的Activity. 它可以显示在Activity中,然后它也可以显示出一些内容. 因为它拥有自己的生命周期 ...

  4. TouTiao开源项目 分析笔记10 实现通用普通文章片段页面

    1.RxJava的Observable数据操作符总结 1.1.Map操作符 Map操作符对原始Observable发射的没一项数据应用一个你选择的函数, 然后返回一个发射这些结果的Observable ...

  5. Android 支付宝H5 没有回调

    今天测试反馈问题,说,手机上没有安装支付宝的,调用支付宝支付之后,没有回调.不提示成功也不提示失败. 我自己试了半天也都是没有问题 .后来终于可以试出来了. 发现原来是,清单里面注册的Activity ...

  6. android stadio mapping文件的使用

    mapping文件就是在对代码混淆以后,你用来查看混淆前和混淆后的对比文件. 一般用来查看线上的bug; java.lang.NullPointerException: Attempt to invo ...

  7. sql中给逗号分隔的查询结果替换单引号

    技术交流群:233513714 第一种方法: SELECT * FROM pay_inf_config a WHERE a.id IN ( SELECT REPLACE ( concat('''', ...

  8. Centos7 grep命令简介

    grep 是一个最初用于 Unix 操作系统的命令行工具.在给出文件列表或标准输入后,grep会对匹配一个或多个正则表达式的文本进行搜索,并只输出匹配(或者不匹配)的行或文本. grep 可根据提供的 ...

  9. 【02】webstorm配置babel转换器+截图(by魔芋)

    [02]webstorm配置babel转换器+截图(by魔芋)   [02]魔芋的安装过程     01,配置babel.   02,用webstorm.注意webstorm的版本号.   03,使用 ...

  10. Quartus 11进行编译Compile Design的时候出现错误near text ã

    1. 设计的工程在Compile Design的时候出现以下的错误,百思不得姐 Error (): Verilog HDL syntax error at div_5.v() near text ã ...