ListView優(yōu)化技巧
一、上節(jié)回顧:
(一)、充分理解convertView的作用:
1、手機(jī)程序運(yùn)行后的效果圖:

2、剛運(yùn)行后的LogCat記錄:

3、屏幕滑動(dòng)后的效果截圖:

4、屏幕滑動(dòng)后的LogCat記錄:

【說(shuō)明:】手機(jī)屏幕中一次展示10條數(shù)據(jù),所以第一次加載時(shí),新建了10個(gè)ViewHolder對(duì)象。這10個(gè)對(duì)象的id從截圖中可以看到:@411e8a18、@413ab880等等。
當(dāng)屏幕滑動(dòng),有些item滑出屏幕,又有新的item從底端進(jìn)入屏幕。可以看到新item進(jìn)入屏幕時(shí)只有一個(gè)是新建ViewHolder,其他的都是重復(fù)使用convertView。
二、ListView優(yōu)化中的細(xì)節(jié)問(wèn)題:
1、android:layout_height屬性:
????? ? 必須將ListView的布局高度屬性設(shè)置為非“wrap_content”(可以是“match_parent / ?fill_parent ?/ ?400dp等絕對(duì)數(shù)值”),如果ListView的布局高度為“wrap_content”,那么getView()就會(huì)重復(fù)調(diào)用。一般來(lái)說(shuō),一個(gè)item會(huì)被調(diào)用四次左右。
2、ViewHolder:
????? ? 利用ViewHolder內(nèi)部類,將item布局文件中需要展示的控件定義為屬性(其實(shí)ViewHolder就是一個(gè)自定義的模型類)。這樣就把item中散在的多個(gè)控件合成一個(gè)整體,這樣可以有效地避免圖片錯(cuò)位。
3、convertView:
? ? ? ? ListView的加載是一個(gè)item一個(gè)item的加載,這樣就會(huì)每次都inflate一個(gè)item布局,然后findViewById一遍該布局上的所有控件。當(dāng)數(shù)據(jù)量大的時(shí)候,是不可想象的。而利用Recycle回收利用就可以解決問(wèn)題。所以要善于重復(fù)利用convertView,這樣可以減少填充布局的過(guò)程,減少ViewHolder對(duì)象實(shí)例化的次數(shù)。減少內(nèi)存開(kāi)銷,提高性能。
4、convertView的setTag():
????? ? 利用setTag()方法將ViewHolder對(duì)象作為標(biāo)簽附加到convertView上,當(dāng)convertView被重復(fù)利用的時(shí)候,因?yàn)樯厦嬗蠽iewHolder對(duì)象,所以convertView就具有了ViewHolder中的幾個(gè)屬性,這樣就節(jié)省了findViewById()這個(gè)過(guò)程。如果一個(gè)item有三個(gè)控件,如果有100條item,那么在加載數(shù)據(jù)過(guò)程中,就就相當(dāng)于節(jié)省了幾百次findViewById(),節(jié)約了執(zhí)行findViewById()的時(shí)間,提升了加載速度,節(jié)省了性能的開(kāi)銷。
5、LayoutInflater對(duì)象的inflate()方法:
? ??inflate()方法一般接收兩個(gè)參數(shù),第一個(gè)參數(shù)就是要加載的布局id,第二個(gè)參數(shù)是指給該布局的外部再嵌套一層父布局,如果不需要就直接傳null。
? ??inflate()方法還有個(gè)接收三個(gè)參數(shù)的方法重載
1. 如果root為null,attachToRoot將失去作用,設(shè)置任何值都沒(méi)有意義。2. 如果root不為null,attachToRoot設(shè)為true,則會(huì)在加載的布局文件的最外層再嵌套一層root布局。3. 如果root不為null,attachToRoot設(shè)為false,則root參數(shù)失去作用。4. 在不設(shè)置attachToRoot參數(shù)的情況下,如果root不為null,attachToRoot參數(shù)默認(rèn)為true。
????? ? 所以在使用LayoutInflater填充布局的時(shí)候,要注意inflate()方法的參數(shù)。如果是兩個(gè)參數(shù),則第二個(gè)參數(shù)可以采用null;如果使用三個(gè)參數(shù)的方法,則要注意參數(shù)之間的搭配。
【備注:】
獲取填充器的三種方法:
LayoutInflater inflater =?getLayoutInflater();
LayoutInflater inflater = (LayoutInflater)?getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
6、監(jiān)聽(tīng)屏幕的滾動(dòng)狀態(tài)的變動(dòng)情況:
? ? ListView對(duì)象有OnScrollListener監(jiān)聽(tīng)器。其回調(diào)方法onScrollStateChanged(AbsListView view, int scrollState)的第二個(gè)參數(shù)就是屏幕滾動(dòng)狀態(tài)。
? scrollState = SCROLL_STATE_TOUCH_SCROLL(1):表示正在滾動(dòng)。當(dāng)屏幕滾動(dòng)且用戶使用的觸碰或手指還在屏幕上時(shí)為1
? scrollState =SCROLL_STATE_FLING(2) :表示手指做了拋的動(dòng)作(手指離開(kāi)屏幕前,用力滑了一下,屏幕產(chǎn)生慣性滑動(dòng))。
? scrollState =SCROLL_STATE_IDLE(0) :表示屏幕已停止。屏幕停止?jié)L動(dòng)時(shí)為0。
? ? 在以上三種屏幕滾動(dòng)狀態(tài)中,如果還處于SCROLL_STATE_FLING狀態(tài),則說(shuō)明屏幕還處于慣性滑動(dòng)狀態(tài),此時(shí)可以不進(jìn)行異步加載圖片。這樣可以節(jié)省不必要的性能開(kāi)銷。
7、item中如果包含button,則事件會(huì)發(fā)生沖突。如何解決控件之間的事件沖突,將在Android事件分發(fā)機(jī)制(touch event)中講解。