Android之ListView优化
關于ListView幾個方面的優(yōu)化:
?
Android中有一個反復循環(huán)構(gòu)件(Recycler),它的工作原理如下:(參考:http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html)
?
?
?
代碼示例:
1 public class ListViewActivity extends Activity { 2 private ArrayList<String> list = new ArrayList<>(); 3 private ListView listView; 4 private ItemAdapter itemAdapter; 5 private int index = 0; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState); 10 setContentView(R.layout.activity_list_view); 11 listView = (ListView) findViewById(R.id.listView); 12 initData(); 13 itemAdapter = new ItemAdapter(); 14 listView.setAdapter(itemAdapter); 15 16 } 17 18 public void initData(){ 19 for(int i = 0; i < 50; i++){ 20 list.add("item--" + index++); 21 } 22 } 23 class ItemAdapter extends BaseAdapter { 24 25 @Override 26 public int getCount() { 27 return list.size(); 28 } 29 30 @Override 31 public Object getItem(int position) { 32 if(position >= 0 && position < list.size()) return list.get(position); 33 return null; 34 } 35 36 @Override 37 public long getItemId(int position) { 38 return position; 39 } 40 41 @Override 42 public View getView(int position, View convertView, ViewGroup parent) { 43 Log.e("getView:--" + position, convertView + ""); 44 ViewHolder vh; 45 if(convertView == null){ 46 convertView = getLayoutInflater().inflate(R.layout.list_item, null); 47 vh = new ViewHolder(); 48 vh.textView = (TextView) convertView.findViewById(R.id.textView); 49 convertView.setTag(vh); 50 }else{ 51 vh = (ViewHolder) convertView.getTag(); 52 } 53 vh.textView.setText("item--" + position); 54 return convertView; 55 } 56 57 class ViewHolder{ 58 TextView textView; 59 } 60 } 61 }?
一、ListView的大小設定固定值
首先需要了解Adapter的使用,里面有一個getCount()是返回ListView要顯示的item個數(shù),而手機界面可以顯示的個數(shù)是通過: ListView的高度/item的高度 。getView()方法是需要返回一個視圖,如果ListView的高度不確定,而是使用wrap_content屬性,那么ListView在匹配的時候,就會在一直在嘗試可以顯示多少個item在ListView上,那么會影響到性能問題。
<ListViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/listView"android:layout_alignParentTop="true"android:layout_alignParentStart="true" />?
1. 如果在layout里面沒有設置ListView的高度為定值時,觀察如下現(xiàn)象:
10-20 17:01:59.857 21761-21761/com.example.lenovo.listviewtest E/getView:--0﹕ null
10-20 17:01:59.870 21761-21761/com.example.lenovo.listviewtest E/getView:--1﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.870 21761-21761/com.example.lenovo.listviewtest E/getView:--2﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.870 21761-21761/com.example.lenovo.listviewtest E/getView:--3﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.870 21761-21761/com.example.lenovo.listviewtest E/getView:--4﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.874 21761-21761/com.example.lenovo.listviewtest E/getView:--5﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.874 21761-21761/com.example.lenovo.listviewtest E/getView:--6﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.874 21761-21761/com.example.lenovo.listviewtest E/getView:--7﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.934 21761-21761/com.example.lenovo.listviewtest E/getView:--0﹕ android.widget.LinearLayout{42994980 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.937 21761-21761/com.example.lenovo.listviewtest E/getView:--1﹕ null
10-20 17:01:59.940 21761-21761/com.example.lenovo.listviewtest E/getView:--2﹕ null
10-20 17:01:59.944 21761-21761/com.example.lenovo.listviewtest E/getView:--3﹕ null
10-20 17:01:59.947 21761-21761/com.example.lenovo.listviewtest E/getView:--4﹕ null
10-20 17:01:59.947 21761-21761/com.example.lenovo.listviewtest E/getView:--5﹕ null
10-20 17:01:59.950 21761-21761/com.example.lenovo.listviewtest E/getView:--6﹕ null
10-20 17:01:59.950 21761-21761/com.example.lenovo.listviewtest E/getView:--7﹕ null
10-20 17:01:59.957 21761-21761/com.example.lenovo.listviewtest E/getView:--0﹕ null
10-20 17:01:59.957 21761-21761/com.example.lenovo.listviewtest E/getView:--1﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.957 21761-21761/com.example.lenovo.listviewtest E/getView:--2﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.957 21761-21761/com.example.lenovo.listviewtest E/getView:--3﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.957 21761-21761/com.example.lenovo.listviewtest E/getView:--4﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.960 21761-21761/com.example.lenovo.listviewtest E/getView:--5﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.960 21761-21761/com.example.lenovo.listviewtest E/getView:--6﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
10-20 17:01:59.960 21761-21761/com.example.lenovo.listviewtest E/getView:--7﹕ android.widget.LinearLayout{429a2fa0 V.E..... ......I. 0,0-0,0}
.....
2. 如果設置ListView的高度為定值時,觀察如下現(xiàn)象:
10-20 17:13:31.624 29386-29386/com.example.lenovo.listviewtest E/getView:--0﹕ null
10-20 17:13:31.631 29386-29386/com.example.lenovo.listviewtest E/getView:--1﹕ null
10-20 17:13:31.634 29386-29386/com.example.lenovo.listviewtest E/getView:--2﹕ null
10-20 17:13:31.638 29386-29386/com.example.lenovo.listviewtest E/getView:--3﹕ null
10-20 17:13:31.641 29386-29386/com.example.lenovo.listviewtest E/getView:--4﹕ null
10-20 17:13:31.644 29386-29386/com.example.lenovo.listviewtest E/getView:--5﹕ null
10-20 17:13:31.644 29386-29386/com.example.lenovo.listviewtest E/getView:--6﹕ null
10-20 17:13:31.651 29386-29386/com.example.lenovo.listviewtest E/getView:--7﹕ null
10-20 17:20:42.501 29386-29386/com.example.lenovo.listviewtest E/getView:--8﹕ null
10-20 17:20:42.614 29386-29386/com.example.lenovo.listviewtest E/getView:--9﹕ android.widget.LinearLayout{4299bd90 V.E..... ........ 0,-133-656,7}
10-20 17:20:42.698 29386-29386/com.example.lenovo.listviewtest E/getView:--10﹕ android.widget.LinearLayout{4299e9b8 V.E..... ........ 0,-128-656,12}
10-20 17:20:42.751 29386-29386/com.example.lenovo.listviewtest E/getView:--11﹕ android.widget.LinearLayout{4299fda0 V.E..... ........ 0,-138-656,2}
10-20 17:20:42.851 29386-29386/com.example.lenovo.listviewtest E/getView:--12﹕ android.widget.LinearLayout{429a1188 V.E..... ........ 0,-129-656,11}
10-20 17:20:42.998 29386-29386/com.example.lenovo.listviewtest E/getView:--13﹕ android.widget.LinearLayout{429a2570 V.E..... ........ 0,-137-656,3}
10-20 17:20:50.464 29386-29386/com.example.lenovo.listviewtest E/getView:--14﹕ android.widget.LinearLayout{429a3958 V.E..... ........ 0,-138-656,2}
10-20 17:20:58.315 29386-29386/com.example.lenovo.listviewtest E/getView:--15﹕ android.widget.LinearLayout{429a4d40 V.E..... ........ 0,-140-656,0}
結(jié)論:
由以上比較可以知道,設定ListView的屬性時,為了提高匹配的效率,可以把ListView的高度設為確定值。
?
二、復用convertView,?使用ViewHolder提高在容器中查找組件的效率
1. ?上面的代碼已經(jīng)重復使用了convertView了,如果每次都是重新對item中的布局實例化成View對象,view =?getLayoutInflater().inflate(R.layout.list_item, null);?這是比較耗時的。
view = getLayoutInflater().inflate(R.layout.list_item, null);Log.e("getView:--" + position, view + "");
10-20 19:35:03.723 18046-18046/com.example.lenovo.listviewtest E/getView:--0﹕ android.widget.LinearLayout{42998e50 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.730 18046-18046/com.example.lenovo.listviewtest E/getView:--1﹕ android.widget.LinearLayout{4299bec0 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.733 18046-18046/com.example.lenovo.listviewtest E/getView:--2﹕ android.widget.LinearLayout{4299d570 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.737 18046-18046/com.example.lenovo.listviewtest E/getView:--3﹕ android.widget.LinearLayout{4299ec20 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.740 18046-18046/com.example.lenovo.listviewtest E/getView:--4﹕ android.widget.LinearLayout{429a02d0 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.743 18046-18046/com.example.lenovo.listviewtest E/getView:--5﹕ android.widget.LinearLayout{429a1980 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.747 18046-18046/com.example.lenovo.listviewtest E/getView:--6﹕ android.widget.LinearLayout{429a3030 V.E..... ......I. 0,0-0,0}
10-20 19:35:03.750 18046-18046/com.example.lenovo.listviewtest E/getView:--7﹕ android.widget.LinearLayout{429a46e0 V.E..... ......I. 0,0-0,0}
10-20 19:35:11.330 18046-18046/com.example.lenovo.listviewtest E/getView:--8﹕ android.widget.LinearLayout{429a9638 V.E..... ......I. 0,0-0,0}
10-20 19:35:13.503 18046-18046/com.example.lenovo.listviewtest E/getView:--0﹕ android.widget.LinearLayout{429ab200 V.E..... ......I. 0,0-0,0}
10-20 19:35:15.697 18046-18046/com.example.lenovo.listviewtest E/getView:--8﹕ android.widget.LinearLayout{429ad050 V.E..... ......I. 0,0-0,0}
10-20 19:35:18.773 18046-18046/com.example.lenovo.listviewtest E/getView:--8﹕ android.widget.LinearLayout{429aed90 V.E..... ......I. 0,0-0,0}
10-20 19:35:20.477 18046-18046/com.example.lenovo.listviewtest E/getView:--9﹕ android.widget.LinearLayout{429b0888 V.E..... ......I. 0,0-0,0}
10-20 19:35:20.634 18046-18046/com.example.lenovo.listviewtest E/getView:--10﹕ android.widget.LinearLayout{429b21c0 V.E..... ......I. 0,0-0,0}
10-20 19:35:21.484 18046-18046/com.example.lenovo.listviewtest E/getView:--2﹕ android.widget.LinearLayout{429b3ba8 V.E..... ......I. 0,0-0,0}
10-20 19:35:21.604 18046-18046/com.example.lenovo.listviewtest E/getView:--1﹕ android.widget.LinearLayout{429b54e0 V.E..... ......I. 0,0-0,0}
10-20 19:35:21.680 18046-18046/com.example.lenovo.listviewtest E/getView:--0﹕ android.widget.LinearLayout{429b6d90 V.E..... ......I. 0,0-0,0}
2. ?上面的例子是一個view就一個TextView組件,但是如果當item的結(jié)構(gòu)比較復雜時,通過convertView.findById()來查找每個組件id就會很費時,如果建立一個ViewHold的話,就避免了在view容器中查找組件的耗時工作了。
10-20 20:08:49.140 3604-3604/com.example.lenovo.listviewtest E/getView:--0﹕ null
10-20 20:08:49.146 3604-3604/com.example.lenovo.listviewtest E/getView:--1﹕ null
10-20 20:08:49.150 3604-3604/com.example.lenovo.listviewtest E/getView:--2﹕ null
10-20 20:08:49.153 3604-3604/com.example.lenovo.listviewtest E/getView:--3﹕ null
10-20 20:08:49.156 3604-3604/com.example.lenovo.listviewtest E/getView:--4﹕ null
10-20 20:08:49.160 3604-3604/com.example.lenovo.listviewtest E/getView:--5﹕ null
10-20 20:08:49.160 3604-3604/com.example.lenovo.listviewtest E/getView:--6﹕ null
10-20 20:08:49.163 3604-3604/com.example.lenovo.listviewtest E/getView:--7﹕ null
10-20 20:08:53.760 3604-3604/com.example.lenovo.listviewtest E/getView:--8﹕ null
10-20 20:08:55.023 3604-3604/com.example.lenovo.listviewtest E/getView:--9﹕ android.widget.LinearLayout{42999078 V.E..... ........ 0,-137-656,3} ? ?//item--0 ? convertView = Recycler中的type1
10-20 20:08:56.040 3604-3604/com.example.lenovo.listviewtest E/getView:--9﹕ android.widget.LinearLayout{42999078 V.E..... ........ 0,1072-656,1212}
10-20 20:08:56.190 3604-3604/com.example.lenovo.listviewtest E/getView:--10﹕ android.widget.LinearLayout{4299c098 V.E..... ........ 0,-132-656,8} ?//item--1 ? convertView = Recycler中的type2
10-20 20:08:57.153 3604-3604/com.example.lenovo.listviewtest E/getView:--11﹕ android.widget.LinearLayout{4299d498 V.E..... ........ 0,-139-656,1}
10-20 20:08:58.500 3604-3604/com.example.lenovo.listviewtest E/getView:--12﹕ android.widget.LinearLayout{4299e898 V.E..... ........ 0,-132-656,8}
10-20 20:09:00.160 3604-3604/com.example.lenovo.listviewtest E/getView:--13﹕ android.widget.LinearLayout{4299fc98 V.E..... ........ 0,-134-656,6}
10-20 20:09:00.343 3604-3604/com.example.lenovo.listviewtest E/getView:--14﹕ android.widget.LinearLayout{429a1098 V.E..... ........ 0,-130-656,10}
10-20 20:09:02.023 3604-3604/com.example.lenovo.listviewtest E/getView:--15﹕ android.widget.LinearLayout{429a2498 V.E..... ........ 0,-139-656,1}
10-20 20:09:03.957 3604-3604/com.example.lenovo.listviewtest E/getView:--16﹕ android.widget.LinearLayout{429a3898 V.E..... ........ 0,-135-656,5}
10-20 20:09:06.000 3604-3604/com.example.lenovo.listviewtest E/getView:--7﹕ android.widget.LinearLayout{429a3898 V.E..... ........ 0,1053-656,1193}
10-20 20:09:06.137 3604-3604/com.example.lenovo.listviewtest E/getView:--6﹕ android.widget.LinearLayout{429a2498 V.E..... ........ 0,1043-656,1183} //item--6 ?從convertView中取得
10-20 20:09:06.270 3604-3604/com.example.lenovo.listviewtest E/getView:--5﹕ android.widget.LinearLayout{429a1098 V.E..... ........ 0,1063-656,1203}
?
在滑動ListView的時候,當最下面顯示item--9的時候,item--0就存在Recycler的type1中,當convertView就不會為null了,同時通過觀察以上的getView--15可以知道,此時item--6的視圖在Recycler中,當向上滑動ListView顯示到getView--6的時候,是從convertView中獲取的,而不是新實例化layout得到的。
?
總結(jié): 通過對比,顯然復用convertView可以提高ListView的顯示效略,起到優(yōu)化作用。同時如果item內(nèi)部的組件多的時候,建議使用ViewHold, 可以提高在view容器中查找組件的效率。
?
?
三、使用分頁加載數(shù)據(jù)
?當客戶端從服務端獲取數(shù)據(jù)量過大,一般為用戶考慮流量,我們都需要對數(shù)據(jù)進行分頁加載(特別是圖片的加載),就上面的例子,模擬ListView的分頁顯示和下拉刷新功能。需要用到ListView的滾動監(jiān)聽。
1 public class ListViewActivity extends Activity implements AbsListView.OnScrollListener{ 2 private Vector<String> list = new Vector<>(); //Vector保證線程安全 3 private ListView listView; 4 private ItemAdapter itemAdapter; 5 private int index = 0; 6 private int count = 0; 7 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 setContentView(R.layout.activity_list_view); 12 listView = (ListView) findViewById(R.id.listView); 13 listView.addFooterView(getLayoutInflater().inflate(R.layout.footer_view, null)); 14 initData(); 15 itemAdapter = new ItemAdapter(); 16 listView.setAdapter(itemAdapter); 17 listView.setOnScrollListener(this); 18 } 19 20 public void initData(){ 21 for(int i = 0; i < 20; i++){ 22 list.add("item--" + index++); 23 } 24 } 25 26 private Handler handler = new Handler(){ 27 @Override 28 public void handleMessage(Message msg) { 29 if(msg.what == 100){ 30 itemAdapter.notifyDataSetChanged(); //adapter更新數(shù)據(jù),listView變化 31 } 32 } 33 }; 34 35 Runnable r = new Runnable() { 36 @Override 37 public void run() { 38 initData(); 39 try { 40 Thread.sleep(2000); //休眠2秒 41 } catch (InterruptedException e) { 42 e.printStackTrace(); 43 } 44 45 handler.sendEmptyMessage(100); 46 } 47 }; 48 49 @Override 50 public void onScrollStateChanged(AbsListView view, int scrollState) { 51 if(itemAdapter.getCount() == count && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){ 52 new Thread(r).start(); //子線程運行 53 } 54 } 55 56 @Override 57 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 58 count = firstVisibleItem + visibleItemCount - 1; //減1是減去listView的footerView 59 } 60 61 class ItemAdapter extends BaseAdapter { 62 63 @Override 64 public int getCount() { 65 return list.size(); 66 } 67 68 @Override 69 public Object getItem(int position) { 70 if(position >= 0 && position < list.size()) return list.get(position); 71 return null; 72 } 73 74 @Override 75 public long getItemId(int position) { 76 return position; 77 } 78 79 @Override 80 public View getView(int position, View convertView, ViewGroup parent) { 81 Log.e("getView:--" + position, convertView + ""); //觀察convertView值 82 ViewHolder vh; 83 if(convertView == null){ 84 convertView = getLayoutInflater().inflate(R.layout.list_item, null); 85 vh = new ViewHolder(); 86 vh.textView = (TextView) convertView.findViewById(R.id.textView); 87 convertView.setTag(vh); 88 }else{ 89 vh = (ViewHolder) convertView.getTag(); 90 } 91 vh.textView.setText("item--" + position); 92 return convertView; 93 } 94 95 class ViewHolder{ 96 TextView textView; 97 } 98 } 99 } View CodelistView頁腳:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="horizontal" android:layout_width="match_parent" 4 android:layout_height="wrap_content" android:gravity="center_horizontal"> 5 6 <ProgressBar 7 style="?android:attr/progressBarStyleSmall" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:id="@+id/progressBar" /> 11 12 <TextView 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:textAppearance="?android:attr/textAppearanceSmall" 16 android:text="正在努力加載..." 17 android:id="@+id/textView" /> 18 </LinearLayout> View Code?
四、快速滾動時, item中可以不顯示耗時加載的圖片或其他資源
一般情況下需要從網(wǎng)絡獲取圖片顯示需要做緩存處理,那么此時可以實現(xiàn)ListView的滾動監(jiān)聽OnScrollListener接口中的方法:
1 private int startPosition; 2 private int endPosition; 3 @Override 4 public void onScrollStateChanged(AbsListView view, int scrollState) { 5 switch (scrollState){ 6 case SCROLL_STATE_IDLE:{ 7 if(itemAdapter.getCount() == count){ 8 new Thread(r).start(); //子線程運行 9 } 10 11 for(int i = startPosition; i < endPosition; i++){ 12 //可以設置圖片的加載顯示 13 } 14 break; 15 } 16 case SCROLL_STATE_TOUCH_SCROLL: 17 //可以設置圖片的加載顯示 18 //... 19 break; 20 case SCROLL_STATE_FLING: //快速滾動 21 break; 22 23 } 24 } 25 26 @Override 27 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 28 count = firstVisibleItem + visibleItemCount - 1; //減1是減去listView的footerView 29 startPosition = firstVisibleItem; //可視起始的item位置 30 endPosition = count; //可視最后的item位置 31 }?
轉(zhuǎn)載于:https://www.cnblogs.com/denluoyia/p/5980167.html
總結(jié)
以上是生活随笔為你收集整理的Android之ListView优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu java开发环境搭建(jd
- 下一篇: 如何完全卸载VS2010