用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) {
}
}
}
}
}
有錯誤大家一起糾正呀,哈哈哈