1. 程式人生 > >ListView載入網路圖片的優化

ListView載入網路圖片的優化

最近身邊很多的人在問ListView載入網路圖片該如何防止OOM,對於初學者來說ListView雖然平常用的比較多,但大多不知道該如何進行優化。同時,在面試的過程中ListView的優化問題也是最常會被問到的,以前面試中要是你能說出優化ListView的幾個方法,那基本上面試官可能就會認可你的能力了。

       我們來了解一些ListView在載入大量網路圖片的時候存在的常見問題:

       1.效能問題,ListView的滑動有卡頓,不流暢,造成非常糟糕的使用者體驗。

       2.圖片的錯位問題。

       3.圖片太大,載入Bitmap時造成的OOM(Out of memory),也就是棧記憶體溢位。

       4.非同步執行緒丟失的問題。

      針對所存在的問題我們逐個擊破,徹底的掌握ListView的優化問題,有利於我們的學習和工作。

      (一) 效能問題:

       在這個問題上我們可以在Adapter介面卡中中複用convertView 和寫一個內部ViewHolder類來解決。但是如果每個Adapter中都寫一個ViewHolder類會顯得非常的麻煩,下面我給大家一個萬能的ViewHolder類,方便在任何Adapter中呼叫。

  1. publicclass BaseViewHolder {  
  2.         @SuppressWarnings
    ("unchecked")  
  3.         publicstatic <T extends View> T get(View view, int id) {  
  4.             SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();  
  5.             if (viewHolder == null) {  
  6.                 viewHolder = new SparseArray<View>();  
  7.                 view.setTag(viewHolder);  
  8.             }  
  9.             View childView = viewHolder.get(id);  
  10.             if (childView == null) {  
  11.                 childView = view.findViewById(id);  
  12.                 viewHolder.put(id, childView);  
  13.             }  
  14.             return (T) childView;  
  15.         }  
  16. }  

        呼叫BaseViewHolder類的示例程式碼:

  1. if (convertView == null) {  
  2.         convertView = LayoutInflater.from(context).inflate(  
  3.                 R.layout.personplans_item, parent, false);  
  4.     }  
  5.     TextView tv_product_type1 = BaseViewHolder.get(convertView,  
  6.             R.id.tv_product_type1);  

        注意:在BaseViewHolder類中我們看到SparseArray是Android提供的一個工具類 ,用意是用來取代HashMap工具類的。如下圖:

          SparseArray是android裡為<Interger,Object>這樣的Hashmap而專門寫的類,目的是提高效率。具體如何提高效率可以去Android文件查詢一下,這裡就不贅述了。

       (二)圖片錯位問題

       這個問題導致的原因是因為複用ConvertView導致的,在載入大量的Item時,常見的錯位問題。這種問題的解決思路通常是以圖片的Url做為唯一的key,然後setTag中,然後獲取時根據圖片的URL來獲得圖片。

      (三)防止OOM,以及非同步載入。

       關於非同步載入圖片的思路是:

       1.第一次進入時,是沒有圖片的,這時候我們會啟動一個執行緒池,非同步的從網上獲得圖片資料,為了防止圖片過大導致OOM,可以呼叫BitmapFactory中的Options類對圖片進行適當的縮放,最後再顯示主執行緒的ImageView上。

       2.把載入好的圖片以圖片的Url做為唯一的key存入記憶體快取當中,並嚴格的控制好這個快取的大小,防止OOM的發生。

       3.把圖片快取在SD當中,如果沒有SD卡就放在系統的快取目錄cache中,以保證在APP退出後,下次進來能看到快取中的圖片,這樣就可以讓使你的APP不會給客戶呈現一片空白的景象。

       4.使用者第二次進來的時候,載入圖片的流程則是倒序的,首先從內容中看是否存在快取圖片,如果沒有就從SD卡當中尋找,再沒有然後才是從網路中獲取圖片資料。這樣做的既可以提高載入圖片的效率,同時也節約了使用者的流量。

        說完了理論性的東西,我們來開始動手實戰一下吧,下面介紹一個GitHub上一個很輕巧的開源框架LazyListGitHub地址,然後基於它做一些我們想要的效果,關於開源的東西,我們不止要學會用,還要從中能學到東西。眾所周知的Android-Universal-Image-Loader其實就是基於LazyList的一個拓展 ,增加了更多的配置。但是從學習的角度我們還是希望能從原理學起,太多的功能封裝,難免會讓我們暈乎,簡單的功能實現就夠了。

          1.先來看一下執行效果圖:

          2.來看一下LazyList專案的結構:

        構非常的簡單,整個專案的體積才10多k,適合加入我們自己的專案當中去,研究起來也不會覺得難,因為都是最為核心的東西。

       3.呼叫Lazylist的入口:

  1. adapter = new LazyAdapter(this, mStrings);  
  2.         list.setAdapter(adapter);  

         傳入一個裝滿圖片Url地址的字串陣列進去,然後在LazyAdapter中對ListView中的進行顯示。

       4.具體LazyAdapter中呼叫的程式碼是:    

  1. publicclass LazyAdapter extends BaseAdapter {  
  2.     private Activity activity;  
  3.     private String[] data;  
  4.     privatestatic LayoutInflater inflater=null;  
  5.     public ImageLoader imageLoader;   
  6.     public LazyAdapter(Activity a, String[] d) {  
  7.         activity = a;  
  8.         data=d;  
  9.         inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  10.         imageLoader=new ImageLoader(activity.getApplicationContext());  
  11.     }  
  12.     publicint getCount() {  
  13.         return data.length;  
  14.     }  
  15.     public Object getItem(int position) {  
  16.         return position;  
  17.     }  
  18.     publiclong getItemId(int position) {  
  19.         return position;  
  20.     }  
  21.     public View getView(int position, View convertView, ViewGroup parent) {  
  22.         View vi=convertView;  
  23.         if(convertView==null)  
  24.             vi = inflater.inflate(R.layout.item, null);  
  25.            ImageView image=BaseViewHolder.get(vi, R.id.image);  
  26.            ImageView image2=BaseViewHolder.get(vi, R.id.image2);  
  27.            imageLoader.DisplayImage(data[position], image);  
  28.            imageLoader.DisplayImage(data[position], image2);  
  29.         return vi;  
  30.     }  
  31. }  


       5.從上面我們可以看出來其實最重要的封裝顯示圖片的方法就在ImageLoader這個類中。

  1. publicclass ImageLoader {  
  2.     MemoryCache memoryCache=new MemoryCache();  
  3.     FileCache fileCache;  
  4.     private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());  
  5.     ExecutorService executorService;  
  6.     Handler handler=new Handler();//handler to display images in UI thread
  7.     public ImageLoader(Context context){  
  8.         fileCache=new FileCache(context);  
  9.         executorService=Executors.newFixedThreadPool(5);  
  10.     }  
  11.     // 當進入listview時預設的圖片,可換成你自己的預設圖片
  12.     finalint stub_id=R.drawable.stub;  
  13.     publicvoid DisplayImage(String url, ImageView imageView)  
  14.     {  
  15.         imageViews.put(imageView, url);  
  16.         // 先從記憶體快取中查詢
  17.         Bitmap bitmap=memoryCache.get(url);  
  18.         if(bitmap!=null)  
  19.             imageView.setImageBitmap(bitmap);  
  20.         else
  21.         {  
  22.              // 若沒有的話則開啟新執行緒載入圖片
  23.             queuePhoto(url, imageView);  
  24.             imageView.setImageResource(stub_id);  
  25.         }  
  26.     }  
  27.     privatevoid queuePhoto(String url, ImageView imageView)  
  28.     {  
  29.         PhotoToLoad p=new PhotoToLoad(url, imageView);  
  30.         executorService.submit(new PhotosLoader(p));  
  31.     }  
  32.     private Bitmap getBitmap(String url)   
  33.     {  
  34.         File f=fileCache.getFile(url);  
  35.         /** 
  36.          * 先從檔案快取中查詢是否有 
  37.          */
  38. 相關推薦

    ListView載入網路圖片優化

    最近身邊很多的人在問ListView載入網路圖片該如何防止OOM,對於初學者來說ListView雖然平常用的比較多,但大多不知道該如何進行優化。同時,在面試的過程中ListView的優化問題也是最常會被問到的,以前面試中要是你能說出優化ListView的幾個方法,

    詳解ListView載入網路圖片優化,讓你輕鬆掌握!

    最近身邊很多的人在問ListView載入網路圖片該如何防止OOM,對於初學者來說ListView雖然平常用的比較多,但大多不知道該如何進行優化。同時,在面試的過程中ListView的優化問題也是最常會被問到的,以前面試中要是你能說出優化ListView的幾個方法,那基本上

    完美解決ListView載入網路圖片亂跳問題

    先說一下為什麼會出現圖片亂跳。 使用convertView對ListView的每個item優化,item的複用可以有效降低記憶體的佔用,使ListView滑動更為流暢。但會帶來一個問題,當最頂部的item滑出螢幕時,會變成下一個從底部將要滑進來的item。每次滑

    listview中glide載入網路圖片跳躍問題

    當介面上滑快要接觸到imageview的底部時 觸發glide載入圖片 載入完成時就會被拉到圖片的頂端的問題。 第一次寫部落格 可能表達的都會很奇怪吧,記錄一下這個遇到的問題。 百度找了一些方法 設定tag什麼的 無果。想起來這是因為載入圖片時,imageview的高度是w

    Android中通過Picasso來載入網路圖片,並通過ListView顯示出來。

    在使用之前需要將Picasso的jar包匯入。 MainActivity程式碼: import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.o

    ListView使用SimpleAdapter載入網路圖片

    ListView是一種常見的佈局,通過SimpleAdapter載入資料既省力又美觀,常用做法如下: SimpleAdapter mySimpleAdapter = new SimpleAdapter (

    canvas 載入網路圖片遇到的問題

    <canvas id="canvas" width="800" height="500">抱歉,您的瀏覽器不支援canvas元素</canvas> 之前是這樣寫的 var img = new Image();//表示嵌入一個影象物件例項 img.src = thi

    Unity載入網路圖片並顯示在UGUI上,解決載入網路圖片出現問號的問題及其案例分析,例項Demo親測可用

    Unity載入網路圖片並顯示在UGUI上,解決載入網路圖片出現問號的問題及其案例分析,例項Demo親測可用 最近自己在載入網路圖片的時候也遇到了載入的圖片無法顯示或者是問號的問題。下面就分析下為什麼會出現這樣的情況。   首先我們直接上程式碼(比較簡單) using U

    Android之Volley框架載入網路圖片

    更多幹貨 分散式實戰(乾貨) spring cloud 實戰(乾貨) mybatis 實戰(乾貨) spring boot 實戰(乾貨) React 入門實戰(乾貨) 構建中小型網際網路企業架構(乾貨) python 學習持續更

    C++ QT 載入網路圖片、本地圖片

    原始碼下載:C++_QT 載入圖片 QTShowImage.cpp #include "QtShowImage.h" #include <QMovie> #include <QNetworkAccessManager> #include <QUrl> #i

    QQ 玩一玩獲取使用者影象暱稱以及CocosCreator動態載入網路圖片

    文章目錄 1、CocosCreator 載入圖片的幾種方式 2、QQ 玩一玩通過openId獲取使用者影象、暱稱 QQ 玩一玩獲取使用者影象、暱稱以及CocosC

    微信小程式cavans.drawImage方法無法載入網路圖片

    微信小程式cavans.drawImage方法無法載入網路圖片 canvas.drawImage(圖片地址, 起始x座標, 起始y座標, 圖片高, 圖片寬)  圖片地址src不能為網路地址:http://www.域名.com/專案/123.jpg  如果

    android-Picasso請求https載入網路圖片不能顯示的解決方案

    Picasso載入https的圖片載入不出來的解決方案 最近專案中有需求–要顯示https連結的圖片,但是配置好路徑後原生的Picasso死活沒法加載出圖片,最後在網上找到了如下的解決辦法 確認依賴 compile 'com.squareup.ok

    需要載入網路圖片的時候我們在adapter繫結資料裡面解析等到圖片的url

    public void BindData(UserBean.DataBean date){ title.setText(date.getTitle()); data.setText(date.getPrice()+""); String R = ""; i

    使用AsyncTask非同步更新UI介面(載入網路圖片

    寫這個部落格時抽抽了,順便又用了一些WebView的東西,更多webview參見這裡 1.簡單介紹下AsyncTask AsyncTask,是android提供的輕量級的非同步類,可以直接繼承AsyncTask,在類中實現非同步操作,並提供介面反饋當前非同步執行的程度(可以

    使用ImageLoader載入網路圖片時,如何獲取載入進度,如何設定進度條

    使用ImageLoader載入網路圖片的時候,我們有可能會需要顯示一個進度條,這個其實非常容易實現,只需要呼叫這個方法進行設定即可: 注意:首先需要在佈局檔案中新增一個進度條,然後給這個進度條設定進度

    iOS 非同步載入網路圖片,獲取圖片真實尺寸

    專案需求: 在網路上載入一組圖片的資料,並且這組圖片要按照比例展示出來 做法分析: (1)首頁介面上要是使用的圖片控制元件的建立,這裡的高度是用設定的高度,這部分需要在主執行緒完成; (2)第二部部分是獲取圖片的實際尺寸,這部分線上程中完成; (3)然後需要在主執行緒重新整

    瀏覽器載入網路圖片

    一.activity_main.xml佈局檔案 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.andro

    iOS NSThread 多執行緒載入網路圖片

    .m 定義圖片連結 // 圖片連結 #define KURL @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1497938913914&am

    IOS開發之非同步載入網路圖片並快取本地實現瀑布流(一)

    </pre><pre name="code" class="objc"></pre><pre name="code" class="objc">在前面的一篇部落格中,我寫了一個瀑布流照片牆的程式,由於之前的程式載入的圖片是本