關於ListView的getView方法被多次重複呼叫的問題

LoveBugzzz發表於2016-09-17
package com.pxy.demo.adapter;

import java.util.ArrayList;

import com.pxy.demo.R;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;

public class MyAdapter extends BaseAdapter{

	private ArrayList<String> list;
	private Context context;
	
	public MyAdapter(Context context,ArrayList<String> list) {
		super();
		this.context = context;
		this.list = list;
	}

	@Override
	public int getCount() {
		return list == null? 0 :list.size();
	}

	@Override
	public Object getItem(int position) {
		return null;
	}

	@Override
	public long getItemId(int position) {
		return 0;
	}

	@Override
	public View getView(int position, View v, ViewGroup parent) {
		ViewHolder holder = null;
		System.out.println("view = "+v + "  position = " + position);
			if(v == null){
				System.out.println("view = null 時進入方法");
				holder = new ViewHolder();
				v = LayoutInflater.from(context).inflate(R.layout.item, null);
				holder.mButton = (Button) v.findViewById(R.id.btn);
				v.setTag(holder);
			}else{
				holder = (ViewHolder) v.getTag();
		}
		String str = list.get(position);
		if(str!=null){
			holder.mButton.setText(str);
		}
		return v;
	}
	
	private class ViewHolder {
       Button mButton;
	}

}


執行時會發現getView會被重複呼叫多次,假設list.size()=10,getView被呼叫的次數會大於10,原因是當ListView的高度是固定的或者match_parent的時候,listview很容易就能計算出容器內可以顯示多少行。但如果我們使用了“wrap_content,只有在螢幕內控制元件完全載入後才知道到底能顯示多少行資料時,ListView自身便會做一些嘗試性計算,就會導致重複呼叫多次getView(具體請看log輸出日誌)。

具體原因:View在Draw的時候分成兩個階段:measure和layout,在measure階段時主要就是為了計算兩個引數:height和width。而且要注意的是,這是個遞迴的過程,從頂向下,DecorView開始依次呼叫自己子元素的measure。計算完成這兩個引數後就開始layout,最後再是draw的呼叫。對於ListView,當然每一個Item都會被呼叫measure方法,而在這個過程中getView和getCount會被呼叫,而且看使用者的需求,
可能會有很多次呼叫。而為什麼會有很多組次呼叫呢?問題就在於在layout中的決定ListView或者它的父元素的height和width屬性的定義了。match_parent會好一點,計算方法會比較簡單,只要跟父元素的大小相似就行,但是即使是match_parent,也不能給View當飯吃,還是要計算出來具體的dip,所以measure還是會被呼叫,只是可能比wrap_content的少一點。至於自適應的它會一直考量它的寬和高,根據內容(也就是它的子Item)計算寬高。可能這個measure過程會反覆執行,如果父元素也是wrap_content,這個過程會更加漫長。所以,解決方法就是儘量避免自適應,除非是萬不得已,固定大小或者填充的效果會比較好一些。

listview,gridview,有時候getview會呼叫多次,特別是把listview放在viewpager中,很容易卡頓
網上的方法往往只是說,把listview的height固定住或者fill_parent,其實這樣簡單的listview是有效的,但是item如果是複雜的xml,很難實現,或者說無法實現。
究其原因,無非是listview要動態計算有多少個view顯示在裡面,所以需要多次onMeasure,最後才onLayout,而onMeasure可能需要執行多次
這不就行了,我們在adapt裡面的getview中,判斷是否在onmeasure裡,如果在,那麼僅僅mInflater.inflate(R.layout.XXX),然後立刻返回這個
convertView,如果不在onmeasure裡,那麼再去真正的onlayout.
結合這種方法,成功解決了卡頓問題..

相關文章