ListView最終優化方法,絕對流暢
ListView終極優化方法,絕對流暢
listview可以說是Android開發中最常見的UI控制元件了,listview能夠以列表的方式顯示大量同類的資料,這樣問題就產生了,既然是大量資料,就會使用到很多佈局,給佈局繫結資料,listview將佔用大量資源還可能會產生卡頓現象。
private String[] mArrData;
private TextView mTV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTV = (TextView) findViewById(R.id.tvShow);
mArrData = new String[1000];
for (int i = 0; i < 1000; i++) {
mArrData[i] = "Google IO Adapter" + i;
}
mAdapter = new TestAdapter(this, mArrData);
((ListView) findViewById(android.R.id.list)).setAdapter(mAdapter);
}
listview現在最常用也擁有很好的效能的優化方式是在Adapter中使用靜態的ViewHolder,具體程式碼如下:
Activity
private TestAdapter mAdapter;
private String[] mArrData;
private TextView mTV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTV = (TextView) findViewById(R.id.tvShow);
mArrData = new String[1000];
for (int i = 0; i < 1000; i++) {
mArrData[i] = "Google IO Adapter" + i;
}
mAdapter = new TestAdapter(this, mArrData);
((ListView) findViewById(android.R.id.list)).setAdapter(mAdapter);
}
Adapter
private int count = 0;
private long sum = 0L;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 開始計時
long startTime = System.nanoTime();
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
null);
holder = new ViewHolder();
holder.icon1 = (ImageView) convertView.findViewById(R.id.icon1);
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
holder.icon2 = (ImageView) convertView.findViewById(R.id.icon2);
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
convertView.setTag(holder);
}
else{
holder = (ViewHolder)convertView.getTag();
}
holder.icon1.setImageResource(R.drawable.icon);
holder.text1.setText(mData[position]);
holder.icon2 .setImageResource(R.drawable.icon);
holder.text2.setText(mData[position]);
// 停止計時
long endTime = System.nanoTime();
// 計算耗時
long val = (endTime - startTime) / 1000L;
Log.e("Test", "Position:" + position + ":" + val);
if (count < 100) {
if (val < 1000L) {
sum += val;
count++;
}
} else
mTV.setText(String.valueOf(sum / 100L));// 顯示統計結果
return convertView;
}
}
static class ViewHolder {
TextView text1;
ImageView icon1;
TextView text2;
ImageView icon2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 開始計時
long startTime = System.nanoTime();
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
null);
holder = new ViewHolder();
holder.icon1 = (ImageView) convertView.findViewById(R.id.icon1);
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
holder.icon2 = (ImageView) convertView.findViewById(R.id.icon2);
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
convertView.setTag(holder);
}
else{
holder = (ViewHolder)convertView.getTag();
}
holder.icon1.setImageResource(R.drawable.icon);
holder.text1.setText(mData[position]);
holder.icon2 .setImageResource(R.drawable.icon);
holder.text2.setText(mData[position]);
// 停止計時
long endTime = System.nanoTime();
// 計算耗時
long val = (endTime - startTime) / 1000L;
Log.e("Test", "Position:" + position + ":" + val);
if (count < 100) {
if (val < 1000L) {
sum += val;
count++;
}
} else
mTV.setText(String.valueOf(sum / 100L));// 顯示統計結果
return convertView;
}
}
static class ViewHolder {
TextView text1;
ImageView icon1;
TextView text2;
ImageView icon2;
}
在Adapter的程式碼中,在getView方法裡首先判斷convertView是否為空,若為空則載入相應佈局,若不為空則直接使用該佈局,這能夠很有效的使用Android為listview提供的快取機制:只載入一屏的佈局,之後滑動出來的item使用的是之前已經載入的佈局的快取;
而使用靜態的ViewHoulder的目的則是節省了findViewById的時間。如果不使用ViewHolder,每次getView的時候都需要得到一次子佈局,而這也是很耗時並且耗資源的;如果使用了ViewHolder作為子佈局的快取,使用View的setTag方法將快取與每個item繫結,則也可以省去了findViewById的事件;而將ViewHolder設定為static的目的是指在初始化Adapter時初始化一次這個內部類,否則將會在每次建立Adapter時都要初始化一次,而這是沒有必要的。
上述方法能夠解決大部分listview消耗資源以及卡頓的問題,但對於不同的需求的listview來說還會存在其他讓listview卡頓的原因,比如listview的item每次載入時都需要獲得圖片並設定到imageview中,item載入時需要進行大量的計算,item裡的TextView需要設定指定字型;這些耗時的操作都會讓listview滑動起來很卡,帶來不好的體驗;
這幾天我一直在研究Android4.0+系統聯絡人的原始碼,因為我發現,系統聯絡人採用的也是listview佈局,每一個item都有圖片文字,而且使用了fastscroller模式,對聯絡人以首字母進行了分來,同時Adapter還實現了SectionIndexer介面,能夠實現這種.
但是卻一點都不卡,而我自己做的一個類似的介面,卻十分卡頓,很影響使用者體驗;於是我找來了Android體統聯絡人的原始碼,自己建立起來了一個可以執行的程式,然後去研究它是如何實現這麼流暢的listview的;
經過研究我發現系統聯絡人的listview使用的是自定義的listview:PinnedHeaderListView 它的定義是這樣的:
/**
*
A ListView that maintains a header pinned at the top of the list. The
*
pinned header can be pushed up and dissolved as needed.
*/
它給listview加了一個header即顯示在聯絡人介面最上方貼著螢幕頂部的那部分,同時它繼承自AutoScrollListView 而這個AutoScrollListView繼承自listview,對listview進行了一些優化,讓listview在互動到指定的item時更流暢;
看到這裡,於是我使用了這個AutoScrollListView ,但效果不是很明顯,listview還是很卡;在系統聯絡人使用的listview中沒有找到解決方法,我開始研究它的Adapter;研究Adapter發現,系統的Adapter進行了很多層的封裝,完全淡化了geiView方法;使用了很多AsyncTask來載入不同的資料,然後使用了CursorLoader來將載入好的資料新增到Adapter裡,同時還將圖片的載入與資料的載入進行了分離,程式碼邏輯十分複雜;但通過這個我得出了一個結論:不要將任何的耗時操作放在listview的getView方法裡。
在系統聯絡人的這些Adapter裡我發現getView方法中沒有任何的耗時操作,在設定圖片時圖片已經得到,對列表按照字母進行的分類也已經分類好了,存放在一個內部類裡;在得出這個結論之前我嘗試過很多系統聯絡人中的程式碼,但都沒有得到明顯的效果,經過大量的測試我得出了這個結論,並且在測試中得到了驗證。
在我的專案中,listview的每一個item都有一個圖片,和很多TextView,而且所有的TextView都要設定非系統的字型;Adapter使用的是ViewHolder優化,在getView中的程式碼已經很少了,但是還是卡;我的listview中的資料是一個物件的List,在物件裡只存放了item需要展示的圖片的資源ID,或者是圖片的路徑,需要通過一些操作才能獲得圖片,而這些操作其實是很耗時的;於是我將原來的物件進行了更改,將圖片物件直接存放在item對應的物件中,然後再Adapter初始化的時候將這些物件初始化,雖然listview展示所需的時間稍微長了一點,但是結果是listview滑動流暢了很多;接著我又將從assets中獲得字型TypeFace的操作放在了Adapter初始化的方法中,並且將字型通過靜態的變數都存起來,然後再getView中只需為TextView設定一下taptface即可,不需要在從asset中獲取字型所花費的時間;通過上面兩步操作之後,我的listview一點都不卡了,十分流暢。
綜上,listview的優化其實就是去找getView中的耗時操作,然後提取出來,要麼使用非同步的方式為item的佈局設定資料,要是實在需要同步,就只能在Adapter初始化時將資料準備好,然後再getView中只需繫結一下就行。
相關文章
- win10最詳細優化設定_win10怎麼優化最流暢Win10優化
- ListView優化View優化
- Flutter 流暢度優化元件 KeframeFlutter優化元件
- 史上最暢銷遊戲機銷量榜 PS 2絕對優勢登頂遊戲
- iOS效能優化系列篇之“列表流暢度優化”iOS優化
- 04 最優化方法優化
- 已開源!Flutter 流暢度優化元件 KeframeFlutter優化元件
- win10最詳細最佳化設定_win10怎麼最佳化最流暢Win10
- 最流暢的遠端桌面,有沒有最流暢的遠端桌面推薦,具體怎麼使用?
- 運籌優化(十八)--對策論基礎及其最優化求解優化
- 2-VI–ListView的基本使用及優化View優化
- 效能優化(一)APP 啟動優化(不敢說秒開,但是最終優化完真不到 1s)優化APP
- 如何用 GPU硬體層加速優化Android系統的遊戲流暢度GPU優化Android遊戲
- win10和win7哪個好用流暢_win10對比win7流暢度Win10Win7
- win10新版本絕地求生設定 win10絕地求生優化設定方法Win10優化
- TGDC丨維塔士13年老兵,暢談“移植優化”方法論優化
- 浮動、絕對定位脫離文件流的區別
- Win10最佳化指南 提升Win10流暢度讓你的電腦流暢起來Win10
- win10遊戲流暢度怎麼提升_win10提高遊戲流暢度的操作方法Win10遊戲
- Android回顧--(十) ListView的優化和多佈局複用AndroidView優化
- 【Linux】命令終端美化優化Linux優化
- 對「美餐客戶端」設計工作流的優化設計客戶端優化
- SPA 的 SEO 方案對比、最終實踐
- CMA:2022年音樂和流媒體最終報告
- 迴流、重繪及其優化優化
- 數值最優化—優化問題的解(二)優化
- Android應用優化之流暢度實操Android優化
- ListView 與 RecyclerView 簡單對比View
- c#實現最簡快速排序,你絕對可以看懂C#排序
- 絕對是講的最清楚的-NodeJS模組系統NodeJS
- win10最適合打遊戲的版本 win10最穩定流暢的版本Win10遊戲
- 贈書《流暢的Python》Python
- 前端效能優化之節流-throttle前端優化
- js優化之防抖節流JS優化
- C# 記憶體管理優化暢想----前言C#記憶體優化
- win10絕地求生n卡優化怎麼設定_win10絕地求生n卡的設定方法Win10優化
- nodejs路徑處理方法和絕對路徑NodeJS
- python中取絕對值簡單方法總結Python
- win11和win10哪個好用流暢 windows11和windows10全面對比優劣Win10Windows