Why ListView?ListView 如果僅僅出于功能上的需求ListView可能沒有存在的必要,ListView能作的事情基本上ScrollView也能勝任。ListView存在的最根本的原因在于它的高效(如何實現(xiàn)的?).ListView通過對象的復(fù)用從而減少內(nèi)存的消耗,也減少了對象的創(chuàng)建從而也減少的cpu的消耗(在Androidk中創(chuàng)建View對象經(jīng)常伴隨著解析xml)。ListView的本質(zhì)是一張bitmap(當(dāng)然所有的控件文字等在屏幕上看到的最終都會變成bitmap),ListView會按照需求,根據(jù)Adapter提供的信息把需要的Item畫出來顯示在屏幕上,當(dāng)屏幕滾動的時候會重新計算Item的位置并繪制出新的bitmap顯示在屏幕上。這樣聽起來感覺可能不是很高效,但這樣帶的好處就是,每用為一第個Item 創(chuàng)建一個View對象,樣式一樣的對象可以共用一個View對象,減少了內(nèi)存的消耗。而且ListView是事件驅(qū)動的,只有當(dāng)需要的時候才會重新繪制,并且只會 繪制當(dāng)前屏幕上所顯示的Items. How To Use?ListView 離不開Adapter,通常的作法創(chuàng)建一個類繼承BaseAdapter,Override getCount()和getView()等方法。生成這個類的對象,調(diào)用ListView的setAdapter()與ListViw進(jìn)行綁定。 How Does It work?ListView會調(diào)用跟其綁定的Adapter的getCount()方法知道有多少個Item需要展示,然后循環(huán)調(diào)用getView(int position, View convertView, ViewGroup parent)知道第position個Item該怎么畫,并畫出來直到把當(dāng)前的ListView的空間填滿。當(dāng)Adapter當(dāng)中的數(shù)據(jù)改變時,需調(diào)用notifyDataSetChanged ()告訴Adapter數(shù)據(jù)發(fā)生了變化或者給Adapter注冊一個觀察者registerDataSetObserver (DataSetObserver observer)。當(dāng)Adapter得知與其綁定的數(shù)據(jù)己發(fā)生改變時間,會再次調(diào)用getCount()方法,并循環(huán)調(diào)用getView(int position, View convertView, ViewGroup parent)刷新當(dāng)前頁面。
當(dāng)這個ListView 向上滾動需要創(chuàng)建一個Item9 同時,有些對象(比如Item1 )不在顯示區(qū)域?qū)⒖床坏剑@時android 將會把item1 的 引用傳遞給 Adapter.getView() 中的convertView這樣我們就不用再創(chuàng)建一個View來存放Item9,只需要把原來的item1對象作下修改,就可以重復(fù)使用了 ;我們也不用擔(dān)心convertView 是不是正確的類型,這個由系統(tǒng)保證,所以我們要作的就是把convertView 轉(zhuǎn)換(經(jīng)常需要向下轉(zhuǎn)型)成我們自己的View 再給它賦值,in this case :(TextView) convertView.setText(“Item9”);
調(diào)用方法所需要的消耗要比訪問變量高得多,而上面的代碼一次又一次的調(diào)用findViewById()方法,作著重復(fù)的事情。所以我們可以進(jìn)一步進(jìn)行如下優(yōu)化: 創(chuàng)建一個類用來保存一些View的引用,這樣我們就可以直接使用,而不用再調(diào)用findViewById().因為我們所保存的只是引用不是對象本身,所以不用擔(dān)心會占用大量內(nèi)存
![]() 上圖是T-mobile g1上采集的的數(shù)據(jù),現(xiàn)在看來可能現(xiàn)在不是很準(zhǔn)確,但其性能上的差異還是很有參考價值的。 Tips & TricksListView是為了大容量數(shù)據(jù)展示而設(shè)計的。如果數(shù)據(jù)量(Item的數(shù)量)不是很大,且用ListView實現(xiàn)起來比較麻煩,不妨換種思路,不使用ListView,而用ScrollView來實現(xiàn)。 如果Item信息布局比較復(fù)雜或者Item的數(shù)量很多,出于性能的考慮,建議自定義一個View組件實現(xiàn)需要的功能,而不是組合其它控件達(dá)到所要的效果。 ListView滾動變黑:在xml中給ListView增加一個屬性android:cacheColorHint="#00000000" 。當(dāng)ListVIew中有很多Item,有時候需要快速的滾動。比如從第一個Item滾動到第600個Item這個時候,中間的很多Item對用戶來說意義不是很大,但android卻要調(diào)用 adapter.getView()方法將這些Item逐一畫出,并且因為滾動很快用戶不希望有任何的延遲。這在一些低端手機比如g1,是很難作到的。所以google工程師想出的一個辦法是在滾動的時候,讓屏幕變黑用一張黑色bitmap蓋住ListView,而不去繪制中間過程中的很多Item,從而提升性能。 Item有自己的背景蓋住了Selector光標(biāo):在xml中給ListView增加一個屬性:android:drawSelectorOnTop="true"這樣光標(biāo)就會跑到Item上面的圖層,解決我們的問題。 Snippets多選框ListView
帶有進(jìn)度條的ListView,多個子線程刷新各自的進(jìn)度,如果子線程很多那么刷新就會變得很頻繁,我們可以由一個handler負(fù)責(zé)統(tǒng)一刷新,這樣我們就要以增加一些額外條件限制刷新的次數(shù)和條件 分批加載的原理很簡單,給ListView添加一個OnScrollListener監(jiān)聽滾動事件,當(dāng)用戶滾動到屏幕到特定的位置時加載新數(shù)據(jù),并給LIstView加一個正在加載的footerView,當(dāng)加載數(shù)據(jù)結(jié)束時再把這個footerView去掉。 如果有什么疑問,發(fā)現(xiàn)bug或者有更好的想法或者建議,或者附件無法下載。請發(fā)郵件至arthurbrown@163.com 工程源碼 |
|