1. 程式人生 > >ListView的優化總結(一)

ListView的優化總結(一)

ListView作為開發中最常見的控制元件,大部分app都會引用ListView來展示資料,用於使用者互動,正因為ListView過於基礎,這麼常用,所以作為app優化中保持高響應度的ListView 介面就顯得尤為重要了

本文結構 :

1.ListView的執行工作原理
2.convertView的複用優化
3.ViewHolder類的使用
4.基於當前滑動狀態的優化

ListView的執行工作原理

先來一張最經典的ListView工作圖。

在解釋ListView的工作原理之前,我們需要了解一些ListView中的重要機制:
Recycler機制


Recycler機制使用一結合來儲存我們之前已經使用過的所謂”廢棄”的子項view。結合上圖中的示例,在item1被滑動移開當前的螢幕時,會將該item的view收集在Recycler相應的集合中,當作快取並從ListView中移除相關的子view。

接著結合這個圖我們討論一下ListView的工作過程:
ListView剛開始實現時會要求每一個子項進行繪製,剛開始佔滿螢幕的每一子項的view都是從定義的item的xml檔案中inflate出來的,多少個item子項就會建立多少個view。
隨著手指的滑動,當item1完全移出螢幕時,基於Recycler機制,將item1的view給depatch掉,即從listView中取消掉item1的view,同時將item1的view存放於Recycler的集合中,如果第8個item和放入“Recycler”的item的view一致,那麼就會使用”Recycler”裡面的Item來顯示,從而不用再重複inflate一次,這樣大大節省了建立View的工作,在需要顯示大量資料時顯得尤為重要。

convertView的複用優化

基於第一部分的基礎工作原理分析,我們認識到Google在設計ListView時精妙之處,接下來我們看一下基於Recycler機制中關於”廢棄的view”的優化,在繼承了Adapter後,我們會重寫其中的getView()方法。其中的第二個引數convertView就是Recycler中使用過的view.

優化:在getview()中給每一個需要顯示的item生成一個view,如果convertView是空的,我們就需要inflate一個新的view並返回,如果convertView不為空就需要新的view物件,直接使用convertView中的view就可以。

程式碼如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Fruit fruit = getItem(position);
    View view;
    if (convertView == null) {
        view = LayoutInflater.from(getContext()).inflate(resourceId, null);
    } else {
        view = convertView;
    }
    ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
    TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
    fruitImage.setImageResource(fruit.getImageId());
    fruitName.setText(fruit.getName());
    return view;
}

ViewHolder類的使用

在上述的程式碼中我們會發現,getView中的View的每一個元件都需要通過findViewById()得到,在不太複雜的情況下這樣當然也可以,可是當需要在view中需要複雜的邏輯判斷。需要大量的findViewById()操作,不僅編碼繁瑣麻煩容易丟失一些元件,同時大量的findViewById操作也會影響效率。

如果我們將item中的所有元件都放在一個類裡面,那這樣操作時不但可以省下一個一個空間繫結的時間,並且會很全面的繫結。

基於此,我們可以定義個ViewHolder來收集所有元件。
對上面的程式碼進行改進後:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Fruit fruit = getItem(position);
    View view;
    ViewHolder holder;
    if (convertView == null) {
        view = LayoutInflater.from(getContext()).inflate(resourceId, null);
        holder = new ViewHolder(view);
        view.setTag(holder);
    } else {
        view = convertView;
        holder=convertView.getTag();
    }

    holder.fruitImage.setImageResource(fruit.getImageId());
    holder.fruitName.setText(fruit.getName());
    return view;
}





//定義的新的class 作為手機UI 元件的工具,並在建構函式中進行元件的繫結。

private class ViewHolder{
    private ImageView fruitImage;
    private TextView fruitName;
    public ViewHolder(View view ){
        fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
        fruitName = (TextView) view.findViewById(R.id.fruit_name);
    }
}

基於當前滑動狀態的優化

getView中操作UI元件的程式碼工作佔用了ListView中的大量工作。
而我們可以判斷當前使用者對ListView的操作,判斷是否要進行ListView的實際更新。

基於什麼判斷呢?

我們可以給當前的ListView設滑動狀態監聽器,當ListView處於快速滑動狀態時,一般情況下使用者不太關心的頁面的具體資訊。所以我們可以在這個狀態下停止UI元件的更新。在元件停止或者點選觸動的滑動狀態下更新元件的資訊。

效果如下:
基於滑動狀態的優化

實現步驟:
1.在Adapter的實現類的getView方法中設定一個狀態指示是否在滑動

public View getView(int position, View convertView, ViewGroup parent) {
        // convertView
        Log.i(TAG, position + "-.-.-.-.-.-.-" + convertView);
        PicBean pic = lists.get(position);
        Viewholder holder;
         if (convertView == null) {
         convertView = inflater.inflate(R.layout.item_listview, null);
         holder = new Viewholder(convertView);
         convertView.setTag(holder);

         } else {
         holder = (Viewholder) convertView.getTag();
         }
        if (!isScroll) {
            holder.name.setText(pic.getName());
            Long ldate = Long.valueOf(pic.getDesc());
            String date = sDateFormat.format(ldate);
            holder.desc.setText(date);

        } else {
            holder.name.setText("載入中");
            holder.name.setTag(pic.getName());
            Long ldate = Long.valueOf(pic.getDesc());
            String date = sDateFormat.format(ldate);
            holder.desc.setTag(date);
        }

        return convertView;
    }

2.在ListView的使用活動中設定listView的滑動監聽器OnScrollListener並根據狀態設定Adapter實現類中的狀態標識,當屬於停止狀態時,得到當前螢幕中的子項的數目並一一配置UI。

lv_show.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                switch (scrollState) {
                case AbsListView.OnScrollListener.SCROLL_STATE_FLING://手指離開螢幕,但螢幕依然滑動
                    adapter.setScrollState(true);
                    break;
                case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:// 停止滾動
                    adapter.setScrollState(false);
                    int count = view.getChildCount();//得到當前螢幕的子項。
                    //一一為子項設定UI元件
                    for (int i = 0; i < count; i++) {
                        TextView name = (TextView) view.getChildAt(i)
                                .findViewById(R.id.name);
                        TextView date = (TextView) view.getChildAt(i)
                                .findViewById(R.id.desc);
                        if (name.getTag() != null) {
                            name.setText((String) name.getTag());
                        }
                        if (date.getTag() != null) {
                            date.setText((String) date.getTag());
                        }
                    }
                    break;
                case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://手指觸碰滑動
                    adapter.setScrollState(true);
                    break;
                }
            }

本篇是關於ListView的初步分析與優化。
關於ListView的原理以及原始碼,推薦看看ListView工作原理完全解析,帶你從原始碼的角度徹底理解

相關推薦

ListView優化總結

ListView作為開發中最常見的控制元件,大部分app都會引用ListView來展示資料,用於使用者互動,正因為ListView過於基礎,這麼常用,所以作為app優化中保持高響應度的ListView 介面就顯得尤為重要了 本文結構 :

ListView優化總結--Android

ride edittext over 變化 業務 適配器 全部 number moved 3.使用Activity和Delegate與適配器交互 這個內容是從書裏看到的,通過托付模式幫助開發人員把全部的業務邏輯從適配器中移到Activity中。以下是加入電話號碼的樣例

35 個 Java 程式碼效能優化總結

前言 程式碼優化,一個很重要的課題。可能有些人覺得沒用,一些細小的地方有什麼好修改的,改與不改對於程式碼的執行效率有什麼影響呢?這個問題我是這麼考慮的,就像大海里面的鯨魚一樣,它吃一條小蝦米有用嗎?沒用,但是,吃的小蝦米一多之後,鯨魚就被餵飽了。程式碼優化也是一樣,如果專案著眼於儘快無BUG

mysql語句優化總結

Sql語句優化和索引 1.Innerjoin和左連線,右連線,子查詢 A.     inner join內連線也叫等值連線是,left/rightjoin是外連線。 SELECT A.id,A.name,B.id,B.name FROM A LEFT JOIN B ON A

HBase性能優化方法總結

rec inter next memstore 不支持 lena cred 追加 查詢效率 一 表的設計 1.1 Pre-Creating Regions 默認情況下,在創建HBase表的時候會自動創建一個region分區,當導入數據的時候,所有的HBase客戶端都向這

深度學習總結各種優化演算法

一.優化演算法介紹 1.批量梯度下降(Batch gradient descent,BGD) θ=θ−η⋅∇θJ(θ) 每迭代一步,都要用到訓練集的所有資料,每次計算出來的梯度求平均 η代表學習率LR 2.隨機梯度下降(Stochas

java_web項目開發經驗總結

從數據 簡單 處理 開發 事務 傳輸 記錄 承載 基礎上   web項目就像一個動態的記事本,功能很強大,你最初的項目功能調研越給力,項目所能發揮的作用也就越給力。這是因為web網絡的強聯系性,大家都可以通過訪問到自己想要訪問的頁面,頁面裏既可以承載信息,也可以承載做事情的

文檔總結——文檔的概述

理解 需要 軟件需求 是否 研究 strong 開發項目 問題 項目開發 寫完文檔後,本來想寫一篇具體的文檔的總結的,後來看大家都寫的具體文檔總結,於是我就想:我還是寫一些跟大家不一樣的東西吧。 所以,我就說說我對各個文檔的宏觀理解吧。

salesforce零基礎學習七十二項目中的零碎知識點小總結

gin 不同 grant dmi ima -m ron 角色 com 項目終於告一段落,雖然比較苦逼,不過也學到了好多知識,總結一下,以後當作參考。 一.visualforce標簽中使用html相關的屬性使用 曾經看文檔沒有看得仔細,導致開發的時候走了一些彎路。還好得到

OpenGL在MFC中的使用總結——基本框架

palette 接受 white 要求 無效 結構 del 一次 是你 項目中要畫3D顯示的模型,於是要用到OpenGL,加上是在MFC中,並且是在MFC中的ActiveX中使用。再並且鑒於他們程序主框架的設定。常規的方法還不一定能實現。所以還是查過不少資料,在此一一總

操作系統基礎知識總結

一個 快速 會有 處理死鎖 b2c fcm 死鎖 空間 存儲系統 1. 進程和線程的區別 進程 進程,即正在運行的程序,程序從硬盤載入到內存就變成進程。進程是資源的擁有者,每個進程都擁有著自己的內存空間與多個線程。 線程 線程是指令的執行者,是計算機執行指令的基本單元,一個

react native 知識點總結

修改 ltp 組件 改變 set 覆蓋 sta 一個 個數 一、關於react native 版本的升級 參照文檔:http://reactnative.cn/docs/0.45/upgrading.html react-native -v

SEO總結

.com http 分享 com ima 技術 wid -1 ges SEO總結(一)

js基本語法總結

向上取整 取余 轉字符串 結果 lin ase 調試 錯誤 進行 1.js簡介 a)js是一種網頁腳本語言,使得瀏覽器可以與網頁互動。 js的一種基於對象和事件驅動,具有安全性能的腳本語言,腳本語言就是在客戶端的瀏覽器就可以互動響應處理程序的語言,而不需要服務器的處理和響應

JSON必知必會學習總結

tor lint 沒有 script app 對數 數據交換格式 object 什麽 七月第一周,從學校畢業回來上班的第一周。離開一段時候後,再次回來重新工作,有了很多新的認識,不再是實習時那麽混混沌沌了。每天我自己該做什麽,怎麽做,做到什麽程度更清晰了。除了要去完成我負責

PHP學習總結

encode 什麽 code 解決 new span att 面向對象 反斜杠 》PHP 面向對象 使用parent訪問父類的構造方法(__construct)時一定要為當前類繼承要訪問的構造方法 類的構造方法(__construct)在實例化時直接被加載,靜態方法

python初步——基礎總結

python 自動化運維一. 第一個HelloWorld 1. 在linux 執行 (python2.7)[[email protected]/* */ ~]# vim test.py #!/usr/bin/env python

Java IO學習總結

file flush writer directory 創建 str java 資源 tab 一、File 類 Java中不管文件還是目錄都可以使用File類操作,File能新建、刪除、重命名文件和目錄,但是不能訪問文件內容本身,訪問文件內容需要使用輸入輸出流。 Fi

mybatis總結

tran default led sqlserver insert cto src 結果集 obj MyBatis 是支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。MyBatis 消除了幾乎所有的JDBC代碼和參數的手工設置以及結果集的檢索。MyBatis 使用

SSF項目總結

變更 可能 檢測 說服力 結果 項目 總結 實時監控 毫無 作為項目經理,在把握需求變更上需要有高度的敏感,作為一個檢測器,實時監控,項目過程中與客戶方溝通的任何細小的變更,都應該記錄在案,同時 抄送給客戶方,註意這裏抄送給客戶方一定要做,目前項目上吃虧的地方有: 1,有的