淺談Android開(kāi)發(fā)中ListView控件性能的一些優(yōu)化方法
ListView優(yōu)化一直是一個(gè)老生常談的問(wèn)題,不管是面試還是平常的開(kāi)發(fā)中,ListView永遠(yuǎn)不會(huì)被忽略掉,那么這篇文章我們來(lái)看看如何最大化的優(yōu)化ListView的性能。
1.在adapter中的getView方法中盡量少使用邏輯
2.盡最大可能避免GC
3.滑動(dòng)的時(shí)候不加載圖片
4.將ListView的scrollingCache和animateCache設(shè)置為false
5.item的布局層級(jí)越少越好
6.使用ViewHolder
下面就具體來(lái)看一些
1.在adapter中的getView方法中盡量少使用邏輯
不要在你的getView()中寫(xiě)過(guò)多的邏輯代碼,我們可以將這些代碼放在別的地方,例如:
優(yōu)化前的getView():
@Override
public View getView(intposition, View convertView, ViewGroup paramViewGroup) {
Object current_event = mObjects.get(position);
ViewHolder holder =null;if(convertView ==null) {
holder =newViewHolder();
convertView = inflater.inflate(R.layout.row_event,null);
holder.ThreeDimension = (ImageView) convertView.findViewById(R.id.ThreeDim);
holder.EventPoster = (ImageView) convertView.findViewById(R.id.EventPoster);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
//在這里進(jìn)行邏輯判斷,這是有問(wèn)題的
if(doesSomeComplexChecking()) {
holder.ThreeDimention.setVisibility(View.VISIBLE);
}else{
holder.ThreeDimention.setVisibility(View.GONE);
}
// 這是設(shè)置image的參數(shù),每次getView方法執(zhí)行時(shí)都會(huì)執(zhí)行這段代碼,這顯然是有問(wèn)題的
RelativeLayout.LayoutParams imageParams =newRelativeLayout.LayoutParams(measuredwidth, rowHeight);
holder.EventPoster.setLayoutParams(imageParams);
returnconvertView;
}
優(yōu)化后的getView():
@Override
public View getView(intposition, View convertView, ViewGroup paramViewGroup) {
Object object = mObjects.get(position);
ViewHolder holder =null;if(convertView ==null) {
holder =newViewHolder();
convertView = inflater.inflate(R.layout.row_event,null);
holder.ThreeDimension = (ImageView) convertView.findViewById(R.id.ThreeDim);
holder.EventPoster = (ImageView) convertView.findViewById(R.id.EventPoster);
//設(shè)置參數(shù)提到這里,只有第一次的時(shí)候會(huì)執(zhí)行,之后會(huì)復(fù)用
RelativeLayout.LayoutParams imageParams =newRelativeLayout.LayoutParams(measuredwidth, rowHeight);
holder.EventPoster.setLayoutParams(imageParams);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}// 我們直接通過(guò)對(duì)象的getter方法代替剛才那些邏輯判斷,那些邏輯判斷放到別的地方去執(zhí)行了holder.ThreeDimension.setVisibility(object.getVisibility());returnconvertView;
}
2.GC 垃圾回收器
當(dāng)你創(chuàng)建了大量的對(duì)象的時(shí)候,GC就會(huì)頻繁的執(zhí)行,所以在getView()方法中不要?jiǎng)?chuàng)建很多的對(duì)象,最好的優(yōu)化是,不要在ViewHolder以外創(chuàng)建任何對(duì)象,如果你的你的log里面發(fā)現(xiàn)“GC has freed some memory”頻繁出現(xiàn)的話(huà),那你的程序肯定有問(wèn)題了。你可以檢查一下:
a) item布局的層級(jí)是否太深
b) getView()方法中是否有大量對(duì)象存在
c) ListView的布局屬性
3.加載圖片
如果你的ListView中需要顯示從網(wǎng)絡(luò)上下載的圖片的話(huà),我們不要在ListView滑動(dòng)的時(shí)候加載圖片,那樣會(huì)使ListView變得卡頓,所以我們需要再監(jiān)聽(tīng)器里面監(jiān)聽(tīng)ListView的狀態(tài),如果滑動(dòng)的時(shí)候,停止加載圖片,如果沒(méi)有滑動(dòng),則開(kāi)始加載圖片
listView.setOnScrollListener(newOnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView listView,intscrollState) {
//停止加載圖片
if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) {
imageLoader.stopProcessingQueue();
}else{
//開(kāi)始加載圖片
imageLoader.startProcessingQueue();
}
}
@Override
public void onScroll(AbsListView view,intfirstVisibleItem,intvisibleItemCount,inttotalItemCount) {
// TODO Auto-generated method stub}
});
4.將ListView的scrollingCache和animateCache設(shè)置為false
scrollingCache:scrollingCache本質(zhì)上是drawing cache,你可以讓一個(gè)View將他自己的drawing保存在cache中(保存為一個(gè)bitmap),這樣下次再顯示View的時(shí)候就不用重畫(huà)了,而是從cache中取出。默認(rèn)情況下drawing cahce是禁用的,因?yàn)樗膬?nèi)存了,但是它確實(shí)比重畫(huà)來(lái)的更加平滑。而在ListView中,scrollingCache是默認(rèn)開(kāi)啟的,我們可以手動(dòng)將它關(guān)閉。
animateCache:ListView默認(rèn)開(kāi)啟了animateCache,這會(huì)消耗大量的內(nèi)存,因此會(huì)頻繁調(diào)用GC,我們可以手動(dòng)將它關(guān)閉掉
優(yōu)化前的ListView
<android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:cacheColorHint="#00000000" android:divider="@color/list_background_color" android:dividerHeight="0dp" android:listSelector="#00000000" android:smoothScrollbar="true" android:visibility="gone"/>
優(yōu)化后的ListView
<android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:divider="@color/list_background_color" android:dividerHeight="0dp" android:listSelector="#00000000" android:scrollingCache="false" android:animationCache="false" android:smoothScrollbar="true" android:visibility="gone"/>
5.減少item的布局的深度
我們應(yīng)該盡量減少item布局深度,因?yàn)楫?dāng)滑動(dòng)ListView的時(shí)候,這回直接導(dǎo)致測(cè)量與繪制,因此會(huì)浪費(fèi)大量的時(shí)間,所以我們應(yīng)該將一些不必要的布局嵌套關(guān)系去掉。減少item布局深度
6.使用ViewHolder
這個(gè)大家應(yīng)該非常熟悉了,但是不要小看這個(gè)ViewHolder,它可以大大提高我們ListView的性能
ListView的優(yōu)化我們已經(jīng)講完了,如果在你的項(xiàng)目中,這些基本優(yōu)化你還沒(méi)有做到的話(huà),那么你的ListView是有問(wèn)題的,還有很大的提升潛力,以后再使用ListView的時(shí)候,一定要將這幾點(diǎn)考慮進(jìn)去,發(fā)揮它的最大的性能。
附:
此外,如果發(fā)現(xiàn)性能方面的問(wèn)題,以下幾個(gè)常見(jiàn)問(wèn)題也應(yīng)注意:
1..Adapter的getView方法里面convertView沒(méi)有使用setTag和getTag方式;
2.在getView方法里面ViewHolder初始化后的賦值或者是多個(gè)控件的顯示狀態(tài)和背景的顯示沒(méi)有優(yōu)化好,抑或是里面含有復(fù)雜的計(jì)算和耗時(shí)操作;
3.在getView方法里面 inflate的row 嵌套太深(布局過(guò)于復(fù)雜)或者是布局里面有大圖片或者背景所致;
4.Adapter多余或者不合理的notifySetDataChanged;
5.listview 被多層嵌套,多次的onMessure導(dǎo)致卡頓,如果多層嵌套無(wú)法避免,建議把listview的高和寬設(shè)置為fill_parent. 如果是代碼繼承的listview,那么也請(qǐng)你別忘記為你的繼承類(lèi)添加上LayoutPrams,注意高和寬都是fill_parent的; 以往我一般都是將listview的高度設(shè)置成fill_parent,而這次我是設(shè)為wrap_content,這樣做的問(wèn)題在于,ListView沒(méi)有取到實(shí)際的高度,他還要根據(jù)計(jì)算才能確定,而每一次計(jì)算應(yīng)該會(huì)觸發(fā)listview的渲染,所以就會(huì)出現(xiàn)getview的調(diào)用次數(shù)跟正常情況相比多了好幾倍。所以在一般情況下,我建議把listiview在布局文件中的高度總是設(shè)置為:fill_parent(或者match_parent),這不僅僅是getview的調(diào)用次數(shù)問(wèn)題,還涉及到布局的效率。
- android ListView和ProgressBar(進(jìn)度條控件)的使用方法
- Android控件之ListView用法實(shí)例詳解
- Android ExpandableListView展開(kāi)列表控件使用實(shí)例
- Android控件ListView用法(讀取聯(lián)系人示例代碼)
- Android UI控件ExpandableListView基本用法詳解
- android使用ExpandableListView控件實(shí)現(xiàn)小說(shuō)目錄效果的例子
- Android控件之使用ListView實(shí)現(xiàn)時(shí)間軸效果
- Android 自定義彈性L(fǎng)istView控件實(shí)例代碼(三種方法)
- Android編程之控件ListView使用方法
- Android控件ListView使用方法詳解
相關(guān)文章
Android 開(kāi)發(fā)中根據(jù)搜索內(nèi)容實(shí)現(xiàn)TextView中的文字部分加粗
最近遇到一個(gè)需求,需要做一個(gè)搜索功能。搜索的內(nèi)容需要加粗顯示。實(shí)現(xiàn)方法很簡(jiǎn)單,下面通過(guò)本文給大家分享Android 開(kāi)發(fā)中根據(jù)搜索內(nèi)容實(shí)現(xiàn)TextView中的文字部分加粗樣式,非常不錯(cuò),需要的朋友參考下2017-03-03
Android百度地圖應(yīng)用之創(chuàng)建顯示地圖
這篇文章主要為大家詳細(xì)介紹了Android百度地圖應(yīng)用之創(chuàng)建顯示地圖,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
Android開(kāi)機(jī)自啟動(dòng)程序詳解
本篇文章是對(duì)Android開(kāi)機(jī)自啟動(dòng)程序進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Android Http實(shí)現(xiàn)文件的上傳和下載
這篇文章主要為大家詳細(xì)介紹了Android Http實(shí)現(xiàn)文件的上傳和下載,感興趣的小伙伴們可以參考一下2016-08-08
Android 兩個(gè)Fragment之間傳遞數(shù)據(jù)實(shí)例詳解
這篇文章主要介紹了Android 兩個(gè)Fragment之間傳遞數(shù)據(jù)實(shí)例詳解的相關(guān)資料,這里附有實(shí)例代碼,實(shí)現(xiàn)該功能,需要的朋友可以參考下2016-12-12
詳解Android studio如何導(dǎo)入jar包方法
這篇內(nèi)容主要給大家詳細(xì)說(shuō)明了如何導(dǎo)入jar包,以及Android studio遇到的各種問(wèn)題和解決辦法。2017-12-12
Android編程圖片加載類(lèi)ImageLoader定義與用法實(shí)例分析
這篇文章主要介紹了Android編程圖片加載類(lèi)ImageLoader定義與用法,結(jié)合實(shí)例形式分析了Android圖片加載類(lèi)ImageLoader的功能、定義、使用方法及相關(guān)操作注意事項(xiàng),代碼中備有較為詳盡的注釋便于理解,需要的朋友可以參考下2017-12-12
Android實(shí)現(xiàn)簡(jiǎn)單音樂(lè)播放控件
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單音樂(lè)播放控件,提供一個(gè)類(lèi)似網(wǎng)易播放控件的默認(rèn)界面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04

