android ListView異步加載圖片
ListView異步加載圖片是非常實(shí)用的方法,凡是是要通過網(wǎng)絡(luò)獲取圖片資源一般使用這種方法比較好,用戶體驗(yàn)好,不用讓用戶等待下去,下面就說實(shí)現(xiàn)方法,先貼上主方法的代碼
public class AsyncImageLoader {
private HashMap
public AsyncImageLoader() {
imageCache = new HashMap
}
public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
if (imageCache.containsKey(imageUrl)) {
SoftReference
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};
new Thread() {
@Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}.start();
return null;
}
public static Drawable loadImageFromUrl(String url) {
URL m;
InputStream i = null;
try {
m = new URL(url);
i = (InputStream) m.getContent();
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Drawable d = Drawable.createFromStream(i, "src");
return d;
}
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
}
實(shí)現(xiàn)方式:通過傳入圖片的網(wǎng)絡(luò)地址和一個(gè)實(shí)現(xiàn)ImageCallback行為的對象,當(dāng)imageCache存在這個(gè)圖片時(shí)候,返回這個(gè)圖片,當(dāng)imageCache沒有這個(gè)圖片時(shí),實(shí)例一個(gè)異步線程來下載圖片并同時(shí)返回為null,最后在圖片下載完成的時(shí)候,調(diào)用imageLoaded方法。
現(xiàn)說說這個(gè)類設(shè)計(jì)的優(yōu)點(diǎn)吧:1.采用了策略模式;2.使用SoftReference關(guān)鍵字
先說說策略模式,程序里把每次下載圖片完成后所進(jìn)行的操作封裝成一個(gè)ImageCallback抽象類,使系統(tǒng)更靈活,并易于擴(kuò)展。
在Java中內(nèi)存管理,引用分為四大類,強(qiáng)引用HardReference、弱引用WeakReference、軟引用SoftReference和虛引用PhantomReference。它們的區(qū)別也很明顯,HardReference對象是即使虛擬機(jī)內(nèi)存吃緊拋出OOM也不會導(dǎo)致這一引用的對象被回收,而WeakReference等更適合于一些數(shù)量不多,但體積稍微龐大的對象,在這四個(gè)引用中,它是最容易被垃圾回收的,而我們對于顯示類似Android Market中每個(gè)應(yīng)用的App Icon時(shí)可以考慮使用SoftReference來解決內(nèi)存不至于快速回收,同時(shí)當(dāng)內(nèi)存短缺面臨Java VM崩潰拋出OOM前時(shí),軟引用將會強(qiáng)制回收內(nèi)存,最后的虛引用一般沒有實(shí)際意義,僅僅觀察GC的活動狀態(tài),對于測試比較實(shí)用同時(shí)必須和ReferenceQueue一起使用。對于一組數(shù)據(jù),我們可以通過HashMap的方式來添加一組SoftReference對象來臨時(shí)保留一些數(shù)據(jù),同時(shí)對于需要反復(fù)通過網(wǎng)絡(luò)獲取的不經(jīng)常改變的內(nèi)容,可以通過本地的文件系統(tǒng)或數(shù)據(jù)庫來存儲緩存。
最后一句話說的很對,事實(shí)上大多數(shù)情況也是如此。
在說說它的用法吧,通常它作為一個(gè)adapter的一個(gè)變量如:
class BookAdapter extends ArrayAdapter
AsyncImageLoader asyncImageLoader;
Context mContext;
BookAdapter(Context context,List
super(context, 0, data);
asyncImageLoader = new AsyncImageLoader();
mContext = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewCache holder ;
if(convertView==null){
LayoutInflater inflate = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflate.inflate(com.slider.cn.R.layout.list_item , null);
holder = new ViewCache();
holder.icon = (ImageView)convertView.findViewById(com.slider.cn.R.id.note_icon);
holder.name = (TextView)convertView.findViewById(com.slider.cn.R.id.note_name);
holder.date = (TextView)convertView.findViewById(com.slider.cn.R.id.note_date);
convertView.setTag(holder);
}else{
holder = (ViewCache)convertView.getTag();
}
final BookInfo bookInfo = getItem(position);
holder.name.setText(bookInfo.getName().toString());
holder.date.setText(bookInfo.getInfo());
holder.icon.setTag(bookInfo.getUri());
//
Drawable drawable = asyncImageLoader.loadDrawable(bookInfo.getUri(), new ImageCallback() {
@Override
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
ImageView imageViewByTag = (ImageView) BookListView.this.findViewWithTag(bookInfo.getUri());
if (imageViewByTag!=null) {
imageViewByTag.setImageDrawable(imageDrawable);
}else {
//load image failed from Internet
}
}
});
if(drawable==null){
holder.icon.setImageDrawable(drawable_waiting);
[!--empirenews.page--]}else{
holder.icon.setImageDrawable(drawable);
}
return convertView;
}
}
static class ViewCache{
ImageView icon;
TextView name;
TextView date;
}
但是,它好像也有一些不完美的地方,比如說可能會造成同時(shí)下載二十多個(gè)圖片的線程(甚至更多),它沒有對線程的數(shù)量做一個(gè)限制。那就使用固定數(shù)據(jù)的線程池吧,再比如出現(xiàn)重復(fù)加在一個(gè)圖片怎么處理,再比如線程池里線程的優(yōu)先級安排怎么弄呢?(比如你想要最近添加進(jìn)入的線程擁有的優(yōu)先級最高,因?yàn)槟憧偸窍胱钕瓤吹疆?dāng)前的界面的內(nèi)容,而不在乎跳過界面的內(nèi)容什么時(shí)候加在完畢,這里可以說的就太多了,事實(shí)上完成上面的已經(jīng)可以應(yīng)付大多數(shù)應(yīng)用了)