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,有的