編輯:關於Android編程
ListView優化一直是一個老生常談的問題,不管是面試還是平常的開發中,ListView永遠不會被忽略掉,那麼這篇文章我們來看看如何最大化的優化ListView的性能。
1.在adapter中的getView方法中盡量少使用邏輯
2.盡最大可能避免GC
3.滑動的時候不加載圖片
4.將ListView的scrollingCache和animateCache設置為false
5.item的布局層級越少越好
6.使用ViewHolder
下面就具體來看一些
1.在adapter中的getView方法中盡量少使用邏輯
不要在你的getView()中寫過多的邏輯代碼,我們可以將這些代碼放在別的地方,例如:
優化前的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(); } //在這裡進行邏輯判斷,這是有問題的 if(doesSomeComplexChecking()) { holder.ThreeDimention.setVisibility(View.VISIBLE); }else{ holder.ThreeDimention.setVisibility(View.GONE); } // 這是設置image的參數,每次getView方法執行時都會執行這段代碼,這顯然是有問題的 RelativeLayout.LayoutParams imageParams =newRelativeLayout.LayoutParams(measuredwidth, rowHeight); holder.EventPoster.setLayoutParams(imageParams); returnconvertView; }
優化後的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); //設置參數提到這裡,只有第一次的時候會執行,之後會復用 RelativeLayout.LayoutParams imageParams =newRelativeLayout.LayoutParams(measuredwidth, rowHeight); holder.EventPoster.setLayoutParams(imageParams); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); }// 我們直接通過對象的getter方法代替剛才那些邏輯判斷,那些邏輯判斷放到別的地方去執行了holder.ThreeDimension.setVisibility(object.getVisibility());returnconvertView; }
2.GC 垃圾回收器
當你創建了大量的對象的時候,GC就會頻繁的執行,所以在getView()方法中不要創建很多的對象,最好的優化是,不要在ViewHolder以外創建任何對象,如果你的你的log裡面發現“GC has freed some memory”頻繁出現的話,那你的程序肯定有問題了。你可以檢查一下:
a) item布局的層級是否太深
b) getView()方法中是否有大量對象存在
c) ListView的布局屬性
3.加載圖片
如果你的ListView中需要顯示從網絡上下載的圖片的話,我們不要在ListView滑動的時候加載圖片,那樣會使ListView變得卡頓,所以我們需要再監聽器裡面監聽ListView的狀態,如果滑動的時候,停止加載圖片,如果沒有滑動,則開始加載圖片
listView.setOnScrollListener(newOnScrollListener() { @Override public void onScrollStateChanged(AbsListView listView,intscrollState) { //停止加載圖片 if(scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { imageLoader.stopProcessingQueue(); }else{ //開始加載圖片 imageLoader.startProcessingQueue(); } } @Override public void onScroll(AbsListView view,intfirstVisibleItem,intvisibleItemCount,inttotalItemCount) { // TODO Auto-generated method stub} });
4.將ListView的scrollingCache和animateCache設置為false
scrollingCache:scrollingCache本質上是drawing cache,你可以讓一個View將他自己的drawing保存在cache中(保存為一個bitmap),這樣下次再顯示View的時候就不用重畫了,而是從cache中取出。默認情況下drawing cahce是禁用的,因為它太耗內存了,但是它確實比重畫來的更加平滑。而在ListView中,scrollingCache是默認開啟的,我們可以手動將它關閉。
animateCache:ListView默認開啟了animateCache,這會消耗大量的內存,因此會頻繁調用GC,我們可以手動將它關閉掉
優化前的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"/>
優化後的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的布局的深度
我們應該盡量減少item布局深度,因為當滑動ListView的時候,這回直接導致測量與繪制,因此會浪費大量的時間,所以我們應該將一些不必要的布局嵌套關系去掉。減少item布局深度
6.使用ViewHolder
這個大家應該非常熟悉了,但是不要小看這個ViewHolder,它可以大大提高我們ListView的性能
ListView的優化我們已經講完了,如果在你的項目中,這些基本優化你還沒有做到的話,那麼你的ListView是有問題的,還有很大的提升潛力,以後再使用ListView的時候,一定要將這幾點考慮進去,發揮它的最大的性能。
附:
此外,如果發現性能方面的問題,以下幾個常見問題也應注意:
1..Adapter的getView方法裡面convertView沒有使用setTag和getTag方式;
2.在getView方法裡面ViewHolder初始化後的賦值或者是多個控件的顯示狀態和背景的顯示沒有優化好,抑或是裡面含有復雜的計算和耗時操作;
3.在getView方法裡面 inflate的row 嵌套太深(布局過於復雜)或者是布局裡面有大圖片或者背景所致;
4.Adapter多余或者不合理的notifySetDataChanged;
5.listview 被多層嵌套,多次的onMessure導致卡頓,如果多層嵌套無法避免,建議把listview的高和寬設置為fill_parent. 如果是代碼繼承的listview,那麼也請你別忘記為你的繼承類添加上LayoutPrams,注意高和寬都是fill_parent的; 以往我一般都是將listview的高度設置成fill_parent,而這次我是設為wrap_content,這樣做的問題在於,ListView沒有取到實際的高度,他還要根據計算才能確定,而每一次計算應該會觸發listview的渲染,所以就會出現getview的調用次數跟正常情況相比多了好幾倍。所以在一般情況下,我建議把listiview在布局文件中的高度總是設置為:fill_parent(或者match_parent),這不僅僅是getview的調用次數問題,還涉及到布局的效率。
在上一篇文章-安卓開發環境搭建中,我們創建並啟動了eclipse自帶的安卓模擬器,該模擬器不僅啟動慢,而且在使用過程中的反應速度也是出奇的差,經常出現卡機現象。為了解決這
主要是在原來的基礎上添加了如下功能1.進度圓環的顏色是漸變。 2.添加一個進度標尺,類似與鐘表表盤的樣子,用來顯示刻度。3.添加一個進度指示器,三角形的樣子,用來顯示進
1、原來是將EditView放到了popupwindow,發現EditView原有的復制、粘貼、全選、選擇功能失效了,所以便用DialogFragment代替了popup
先上效果圖: Title的Layout為: 彈出的dialog的Layout為