Android中ListView的幾種常見的優(yōu)化方法總結(jié)
Android中的ListView應(yīng)該算是布局中幾種最常用的組件之一了,使用也十分方便,下面將介紹ListView幾種比較常見的優(yōu)化方法:
首先我們給出一個(gè)沒有任何優(yōu)化的Listview的Adapter類,我們這里都繼承自BaseAdapter,這里我們使用一個(gè)包含100個(gè)字符串的List集合來作為L(zhǎng)istView的項(xiàng)目所要顯示的內(nèi)容,每一個(gè)條目都是一個(gè)自定義的組件,這個(gè)組件中只包含一個(gè)textview:
Activity:
package com.alexchen.listviewoptimize; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private ListView lv_demo; private List<String> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lv_demo = (ListView) findViewById(R.id.lv_demo); //list為要加載的條目文本的集合,這里總共是100條 list = new ArrayList<String>(); for (int i = 0; i < 100; i++) { list.add("條目" + i); } lv_demo.setAdapter(new MyAdapter()); } private class MyAdapter extends BaseAdapter { @Override public int getCount() { return list.size(); } @Override public View getView(int position, View convertView, ViewGroup parent) { //listview_item里只有一個(gè)textview View view = View.inflate(MainActivity.this, R.layout.listview_item, null); //使用每一次都findviewById的方法來獲得listview_item內(nèi)部的組件 TextView tv_item = (TextView) view.findViewById(R.id.tv_item); tv_item.setText(list.get(position)); return view; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } } }
優(yōu)化一:
也是最普通的優(yōu)化,就在MyAdapter類中的getView方法中,我們注意到,上面的寫法每次需要一個(gè)View對(duì)象時(shí),都是去重新inflate一個(gè)View出來返回去,沒有實(shí)現(xiàn)View對(duì)象的復(fù)用,而實(shí)際上對(duì)于ListView而言,只需要保留能夠顯示的最大個(gè)數(shù)的view即可,其他新的view可以通過復(fù)用的方式使用消失的條目的view,而getView方法里也提供了一個(gè)參數(shù):convertView,這個(gè)就代表著可以復(fù)用的view對(duì)象,當(dāng)然這個(gè)對(duì)象也可能為空,當(dāng)它為空的時(shí)候,表示該條目view第一次創(chuàng)建,所以我們需要inflate一個(gè)view出來,所以在這里,我們使用下面這種方式來重寫getView方法:
@Override public View getView(int position, View convertView, ViewGroup parent) { View view; // 判斷convertView的狀態(tài),來達(dá)到復(fù)用效果 if (null == convertView) { //如果convertView為空,則表示第一次顯示該條目,需要?jiǎng)?chuàng)建一個(gè)view view = View.inflate(MainActivity.this, R.layout.listview_item, null); } else { //否則表示可以復(fù)用convertView view = convertView; } // listview_item里只有一個(gè)textview TextView tv_item = (TextView) view.findViewById(R.id.tv_item); tv_item.setText(list.get(position)); return view; }
優(yōu)化二:
上面是對(duì)view對(duì)象的復(fù)用做的優(yōu)化,我們經(jīng)過上面的優(yōu)化之后,我們不需要每一個(gè)view都重新生成了。下面我們來解決下一個(gè)每一次都需要做的工作,那就是view中組件的查找:
TextView tv_item = (TextView) view.findViewById(R.id.tv_item);
實(shí)際上,findViewById是到xml文件中去查找對(duì)應(yīng)的id,可以想象如果組件多的話也是挺費(fèi)事的,如果我們可以讓view內(nèi)的組件也隨著view的復(fù)用而復(fù)用,那該是多美好的一件事啊。。實(shí)際上谷歌也推薦了一種優(yōu)化方法來做應(yīng)對(duì),那就是重新建一個(gè)內(nèi)部靜態(tài)類,里面的成員變量跟view中所包含的組件個(gè)數(shù)類型相同,我們這里的view只包含了一個(gè)TextView,所以我們的這個(gè)靜態(tài)類如下:
private static class ViewHolder { private TextView tvHolder; }
那么這個(gè)viewHolder類我們要如何使用才可以達(dá)到復(fù)用效果呢?基本思路就是在convertView為null的時(shí)候,我們不僅重新inflate出來一個(gè)view,并且還需要進(jìn)行findviewbyId的查找工作,但是同時(shí)我們還需要獲取一個(gè)ViewHolder類的對(duì)象,并將findviewById的結(jié)果賦值給ViewHolder中對(duì)應(yīng)的成員變量。最后將holder對(duì)象與該view對(duì)象“綁”在一塊。
當(dāng)convertView不為null時(shí),我們讓view=converView,同時(shí)取出這個(gè)view對(duì)應(yīng)的holder對(duì)象,就獲得了這個(gè)view對(duì)象中的TextView組件,它就是holder中的成員變量,這樣在復(fù)用的時(shí)候,我們就不需要再去findViewById了,只需要在最開始的時(shí)候進(jìn)行數(shù)次查找工作就可以了。這里的關(guān)鍵在于如何將view與holder對(duì)象進(jìn)行綁定,那么就需要用到兩個(gè)方法:setTag和getTag方法了:
@Override public View getView(int position, View convertView, ViewGroup parent) { View view; ViewHolder holder; // 判斷convertView的狀態(tài),來達(dá)到復(fù)用效果 if (null == convertView) { // 如果convertView為空,則表示第一次顯示該條目,需要?jiǎng)?chuàng)建一個(gè)view view = View.inflate(MainActivity.this, R.layout.listview_item, null); //新建一個(gè)viewholder對(duì)象 holder = new ViewHolder(); //將findviewbyID的結(jié)果賦值給holder對(duì)應(yīng)的成員變量 holder.tvHolder = (TextView) view.findViewById(R.id.tv_item); // 將holder與view進(jìn)行綁定 view.setTag(holder); } else { // 否則表示可以復(fù)用convertView view = convertView; holder = (ViewHolder) view.getTag(); } // 直接操作holder中的成員變量即可,不需要每次都findViewById holder.tvHolder.setText(list.get(position)); return view; }
經(jīng)過上面的做法,可能大家感覺不太到優(yōu)化的效果,根據(jù)Google的文檔,實(shí)際優(yōu)化效果在百分之5左右。
優(yōu)化三:
上面的兩個(gè)例子中ListView都是顯示的本地的List集合中的內(nèi)容,List的長(zhǎng)度也只有100個(gè),我們可以毫不費(fèi)力一次性加載完這100個(gè)數(shù)據(jù);但是實(shí)際應(yīng)用中,我們往往會(huì)需要使用Listview來顯示網(wǎng)絡(luò)上的內(nèi)容,比如說我們拿使用ListView顯示新聞為例:
其一:假如網(wǎng)絡(luò)情況很好,我們使用的手機(jī)也許能夠一下子加載完所有新聞數(shù)據(jù),然后顯示在ListView中,用戶可能感覺還好,假如說在網(wǎng)絡(luò)不太順暢的情況下,用戶加載完所有網(wǎng)絡(luò)的數(shù)據(jù),可能這個(gè)list是1000條新聞,那么用戶可能需要面對(duì)一個(gè)空白的Activity好幾分鐘,這個(gè)顯然是不合適的
其二:我們知道Android虛擬機(jī)給每個(gè)應(yīng)用分配的運(yùn)行時(shí)內(nèi)存是一定的,一般性能不太好的機(jī)器只有16M,好一點(diǎn)的可能也就是64M的樣子,假如說我們現(xiàn)在要瀏覽的新聞總數(shù)為一萬條,即便是網(wǎng)絡(luò)很好的情況下,我們可以很快的加載完畢,但是多數(shù)情況下也會(huì)出現(xiàn)內(nèi)存溢出從而導(dǎo)致應(yīng)用崩潰的情況。
那么為了解決上面的兩個(gè)問題,我們需要進(jìn)行分批加載,比如說1000條新聞的List集合,我們一次加載20條,等到用戶翻頁(yè)到底部的時(shí)候,我們?cè)偬砑酉旅娴?0條到List中,再使用Adapter刷新ListView,這樣用戶一次只需要等待20條數(shù)據(jù)的傳輸時(shí)間,不需要一次等待好幾分鐘把數(shù)據(jù)都加載完再在ListView上顯示。其次這樣也可以緩解很多條新聞一次加載進(jìn)行產(chǎn)生OOM應(yīng)用崩潰的情況。
實(shí)際上,分批加載也不能完全解決問題,因?yàn)殡m然我們?cè)诜峙幸淮沃辉黾?0條數(shù)據(jù)到List集合中,然后再刷新到ListView中去,假如有10萬條數(shù)據(jù),如果我們順利讀到最后這個(gè)List集合中還是會(huì)累積海量條數(shù)的數(shù)據(jù),還是可能會(huì)造成OOM的情況,這時(shí)候我們就需要用到分頁(yè),比如說我們將這10萬條數(shù)據(jù)分為1000頁(yè),每一頁(yè)100條數(shù)據(jù),每一頁(yè)加載時(shí)都覆蓋掉上一頁(yè)中List集合中的內(nèi)容,然后每一頁(yè)內(nèi)再使用分批加載,這樣用戶的體驗(yàn)就會(huì)相對(duì)好一些。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android ListView適配器(Adapter)優(yōu)化方法詳解
- Android ListView介紹及優(yōu)化方案
- 實(shí)例講解Android app開發(fā)中ListView的基本使用及優(yōu)化
- 淺談Android開發(fā)中ListView控件性能的一些優(yōu)化方法
- Android編程使用緩存優(yōu)化ListView的方法
- Android ListView優(yōu)化之提高android應(yīng)用效率
- Android中ListView Item布局優(yōu)化技巧
- android listview優(yōu)化幾種寫法詳細(xì)介紹
- Android ListView常見的優(yōu)化方式詳解
相關(guān)文章
android中實(shí)現(xiàn)指針滑動(dòng)的動(dòng)態(tài)效果方法
本次實(shí)現(xiàn)的是類似于墨跡天氣中軌跡圖片上指針隨著數(shù)值滾動(dòng)滑動(dòng)的效果,基本思路是開啟線程,控制指針?biāo)诘膇mageview控件的padding屬性。2013-03-03Android使用RecyclerView實(shí)現(xiàn)列表數(shù)據(jù)選擇操作
這篇文章主要為大家詳細(xì)介紹了Android使用RecyclerView結(jié)合CheckBox實(shí)現(xiàn)列表數(shù)據(jù)選擇操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06Android DrawerLayout實(shí)現(xiàn)側(cè)拉菜單功能
這篇文章主要介紹了Android DrawerLayout實(shí)現(xiàn)側(cè)拉菜單功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06Android學(xué)習(xí)筆記(二)App工程文件分析
之前寫過一篇關(guān)于安卓環(huán)境配置以及第一個(gè)app的制作過程,下面我們來進(jìn)一步,分析下APP工程文件2014-07-07關(guān)于OkHttp中response.body().string()的用法解析
這篇文章主要介紹了關(guān)于OkHttp中response.body().string()的用法解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Android簡(jiǎn)單實(shí)現(xiàn)計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了Android簡(jiǎn)單實(shí)現(xiàn)計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08通過FancyView提供 Android 酷炫的開屏動(dòng)畫實(shí)例代碼
這篇文章主要介紹了通過FancyView提供 Android 酷炫的開屏動(dòng)畫的實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-12-12Android使用AndroidUtilCode實(shí)現(xiàn)多語言
這篇文章主要為大家介紹了Android使用AndroidUtilCode實(shí)現(xiàn)多語言示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01