用ListView用的也不少,但都因为懒而没有深入研究过具体实现,参考了下别人的研究成果,然后自己写了个demo.
对于为什么要用ViewHold这个类,为什么会出现图片闪现、错位等状况,可以用参考下面链接的分析
参考链接:http://www.cnblogs.com/lesliefang/p/3619223.html
我从Adapter类的getView()开始分析,然后是强引用缓存,软引用缓存,本地SDcard缓存,到异步加载图片
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Viewhold viewhold;
if (convertView == null) {
convertView = inflater.inflate(R.layout.item_imagelist, null);
viewhold = new Viewhold();
viewhold.imageView = (ImageView) convertView
.findViewById(R.id.imageView1);
viewhold.textView = (TextView) convertView
.findViewById(R.id.textView1);
convertView.setTag(viewhold);
} else {
viewhold = (Viewhold) convertView.getTag();
}
viewhold.imageView.setTag(urls[position]);<span style="white-space:pre"> </span>//我给要显示的ImageView组件设置一个标志位,通过标志位来判断显示图片的ImageView是不是正在要显示图片的ImageView(感觉有点绕)
viewhold.imageView.setImageResource(R.drawable.ic_launcher);
LoadImage.loadimage(viewhold.imageView, urls[position]);<span style="white-space:pre"> </span>//此处显示完成图片的显示
viewhold.textView.setText("这是" + position + "副图");
return convertView;
}
class Viewhold {
ImageView imageView;
TextView textView;
}
LoadImage类的分析:
public class LoadImage {
public static void loadimage(ImageView imageview, String str) {
Bitmap bitmap = null;
// 从强引用中获取图片资源
bitmap = lrucache.get(str);
if (bitmap != null) {
if (!imageview.getTag().equals(str)) { // 防止错位和闪现
return;
}
imageview.setImageBitmap(bitmap);
return;
}
// 从软应用中获取图片资源
bitmap = getBitmapFromSoftCache(str);
if (bitmap != null) {
if (!imageview.getTag().equals(str)) {
return;
}
imageview.setImageBitmap(bitmap);
// 软引用有此资源则应该添加到强引用中,将来获取就可能从强引用中获得了
lrucache.put(str, bitmap);
return;
}
// 从SDcard中获取图片资源
bitmap = getBitmapFromSDcard(str);
if (bitmap != null) {
if (!imageview.getTag().equals(str)) {
return;
}
imageview.setImageBitmap(bitmap);
// 本地有此资源则应该添加到强引用中,将来获取就可能从强引用中获得了
lrucache.put(str, bitmap);
return;
}
// 异步加载图片
new DownImage(imageview, str).execute(str);
}
// 从SDcard获取图片的具体实现
private static Bitmap getBitmapFromSDcard(String str) {
File rootFile = Environment.getExternalStorageDirectory();
File file = new File(rootFile, "mypics");
if (!file.exists()) {
file.mkdir();
}
File[] files = file.listFiles();
if (files == null) {
return null;
}
String[] split = str.split("/");
String filename = split[split.length - 1];
for (File file1 : files) {
// 逐一匹配名字,满足条件则返回
if (file1.getName().equals(filename)) {
return BitmapFactory.decodeFile(file1.getPath());
}
}
return null;
}
// 强引用的申明,大小一般是用内存大小的1/8
public static LruCache<String, Bitmap> lrucache = new LruCache<String, Bitmap>(
(int) (Runtime.getRuntime().maxMemory() / 8)) {
@Override
protected void entryRemoved(boolean evicted, String key,
Bitmap oldValue, Bitmap newValue) {
if (evicted) {
addsoftcache(key, oldValue);
}
}
@Override
protected int sizeOf(String key, Bitmap value) {
// return value.getByteCount();从这个方法需要有版本要求,用下面方法间接得到图片大小
return value.getHeight() * value.getRowBytes();
}
};
// 软引用申明
public static HashMap<String, SoftReference<Bitmap>> softcache = new HashMap<String, SoftReference<Bitmap>>();
// 从软引用中得到图片资源的具体实现
public static Bitmap getBitmapFromSoftCache(String str) {
// 曾经我在这里摔了一跤,我得到图片直接用softcache.get(str).get(),结果报空指针异常,我还纳闷了半天
// 需要对获得的软引用进行空指针判断,避免空指针,不必要的错误
SoftReference<Bitmap> softReference = softcache.get(str);
if (softReference != null) {
Bitmap bitmap = softReference.get();
if (bitmap != null) {
return bitmap;
}
}
return null;
}
// 添加到软应用中
public static void addsoftcache(String str, Bitmap bitmap) {
softcache.put(str, new SoftReference<Bitmap>(bitmap));
}
// 添加资源到强引用中,在异步加载时,软引用,sdcard有资源时需要调用
public static void addToLruCache(String str, Bitmap bitmap) {
lrucache.put(str, bitmap);
}
}
异步加载的分析
public class DownImage extends AsyncTask<String, Void, Bitmap> {
ImageView imageview;
String urlstr;
public DownImage(ImageView imageview, String urlstr) {
this.imageview = imageview;
this.urlstr = urlstr;
}
// 在工作线程中实现图片的下载操作,同时将结果返回到onPostExecute()中
@Override
protected Bitmap doInBackground(String... params) {
try {
URL url1 = new URL(params[0]);
HttpURLConnection conn = (HttpURLConnection) url1.openConnection();
InputStream is = conn.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
saveBitmapToSDcard(bitmap, params[0]);
LoadImage.addToLruCache(params[0], bitmap);
return bitmap;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Bitmap result) {
if (!imageview.getTag().equals(urlstr)) {
return;
}
imageview.setImageBitmap(result);
saveBitmapToSDcard(result, urlstr);
LoadImage.addToLruCache(urlstr, result);
super.onPostExecute(result);
}
// 保存到SDcard的具体实现
public static void saveBitmapToSDcard(Bitmap bitmap, String str) {
File rootFile = Environment.getExternalStorageDirectory();
File file = new File(rootFile, "mypics");
if (!file.exists()) {
file.mkdir();
}
String[] split = str.split("/");
String filename = split[split.length - 1];
File file2 = new File(file, filename);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file2);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
} catch (FileNotFoundException e) {
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
}
}
}
}
}
有错误大家一起纠正呀,哈哈哈