[Android問答] ListView如何載入遠程圖片?(附代碼)

來源:互聯網
上載者:User

 ListView在Android應用裡扮演非常重要的角色,但很多開發人員在使用ListView時都遇到過不少麻煩。一個常見的問題是:列表中要顯示一系列記錄,每條記錄帶有一張縮圖(產品照片、帳戶圖片等等),而這個縮圖是通過一個遠程URL地址來標識的。這樣的應用情境該如何?呢?

為了避免下載圖片帶來的延遲,所有遠程圖片都應該使用非同步方式載入,即使用單獨的線程下載圖片,待圖片下載完畢後顯示在ImageView裡。Android裡可以像普通Java一樣啟動新線程,但當這個線程要更新介面時,必須使用Handler來請求,否則會為應用程式帶來潛在危害。

RemoteImageHelper

為了將複雜的邏輯分離,我們單獨寫一個名為RemoteImageHelper的類來處理“非同步下載圖片並更新到介面”這個問題,這個類能夠實現以下功能:

  • 圖片開始下載前,ImageView裡顯示一個表示“正在載入”的佔位圖;
  • 圖片在後台下載,下載完成後顯示在ImageView裡;
  • 若圖片下載失敗,ImageView顯示一個表示下載失敗的佔位圖;

下面讓我們來看一下實現代碼:

首先需要有一個方法下載遠程圖片,這裡我們不用把圖片下載到手機上,直接返回一個InputStream類型的結果即可。如果運行時這個方法報錯,請檢查是否在AndroidManifest.xml裡添加了android.permission.INTERNET許可權。

private InputStream download(String urlString) throws MalformedURLException, IOException {    InputStream inputStream = (InputStream) new URL(urlString).getContent();    return inputStream;}

然後是最主要的非同步載入圖片方法,“正在下載”和“下載失敗”的圖片可根據需要自己替換。代碼如下所示:

private final Map<String, Drawable> cache = new HashMap<String, Drawable>();public void loadImage(final ImageView imageView, final String urlString, boolean useCache) {    if (useCache && cache.containsKey(urlString)) {        imageView.setImageDrawable(cache.get(urlString));    }    //Show a "Loading" image here    imageView.setImageResource(R.drawable.image_indicator);    Log.d(this.getClass().getSimpleName(), "Image url:" + urlString);    final Handler handler = new Handler() {        @Override        public void handleMessage(Message message) {            imageView.setImageDrawable((Drawable) message.obj);        }    };    Runnable runnable = new Runnable() {        public void run() {            Drawable drawable = null;            try {                InputStream is = download(urlString);                drawable = Drawable.createFromStream(is, "src");                if (drawable != null) {                    cache.put(urlString, drawable);                }            } catch (Exception e) {                Log.e(this.getClass().getSimpleName(), "Image download failed", e);                //Show a "download fail" image                 drawable = imageView.getResources().getDrawable(R.drawable.image_fail);            }                        //Notify UI thread to show this image using Handler            Message msg = handler.obtainMessage(1, drawable);            handler.sendMessage(msg);        }    };    new Thread(runnable).start();}

關於緩衝:在這個例子裡我們使用一個記憶體中的HashMap作為圖片緩衝,它實現簡單但當應用退出後緩衝就會被清除。在實際項目裡,你可以考慮實現一個基於檔案的緩衝機制,即將下載的圖片儲存到SD卡上,注意要定期清除長期不用的圖片以節約儲存空間。

使用RemoteImageHelper

如何使用這個類呢?下面是一個例子。請注意,為了達到更好的示範效果,代碼裡在調用loadImage()方法時第三個參數用false禁止了圖片緩衝功能,在實際項目中,你很可能需要改為true來避免重複下載圖片以便提高效能。

List<MyRecord> exampleRecords;LazyImageHelper lazyImageHelper = new LazyImageHelper();class MyAdapter extends ArrayAdapter<MyRecord> {    public MyAdapter(Context context) {        super(context, R.layout.record_row, R.id.lblLabel, exampleRecords);    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        View view = super.getView(position, convertView, parent);        MyRecord record = getItem(position);        TextView lblLabel = (TextView) view.findViewById(R.id.lblLabel);        ImageView imageView = (ImageView) view.findViewById(R.id.img);        lblLabel.setText(record.getLabel());        //For demo purpose, cache is DISABLED here.        lazyImageHelper.loadImage(imageView, record.getImageUrl(), false);        //To enable cache, simply use following code:        //lazyImageHelper.loadImage(imageView, record.getImageUrl(), true);        return view;    }}

以上代碼中的MyRecord是一個簡單的POJO類,表示一個業務對象,它具有id、label和imageUrl三個屬性。你可以在完整的工程代碼中找到它。

代碼下載

上述樣本工程編譯後的APK檔案點擊這裡下載,可運行在Android 2.1或以上版本。

上述樣本工程的原始碼點擊這裡下載。

參考資料

Handler

android的訊息處理機制

How do I do a lazy load of images in ListView

Issue 13959:Make listviews more programmer friendly

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.