一:BaseAdapter介绍
BaseAdapter是listview,gridview等列表,使用的数据适配器,它的主要用途是将一组数据传到ListView、Spinner、Gallery及GridView等UI显示组件,如果listView列表的数据项过多,如1000项,我们如果把这1000项全部放到界面中去,软件直接内存溢出了,BaseAdapter刚才可以帮我们解决这个问题,BaseAdapter工作原理图如下:
从上图中看出,如果我们有1000个数据项,实际显示的只有7项,其它的缓存在Recycler中,Recycler类似于消息对列,用来保存未显示在ui上的数据项,如果顶部(或底部)通过滚动,从listView界面中滑出,Recycler就将该数据项,添加到消息对列,如上图中,第一项已经从界面中滑出,当第一项重新滑进的时候,android会判断第一项是否加载过,如果有那么就重新设置第一项的数据源,然后显示。当第一次加载数据项,或者上滑,或者下滑显示数据项的时候,就会调用getView()方法,然而很多时候,getView()方法系统会调用多次,调用多次就会多次刷新界面,性能会降低,比如界面会卡顿等。
/** @params position 需要显示的数据下标,从0开始 @params view 显示的视图 @ViewGroup 视图的组 */ public View getView(int position, View view, ViewGroup viewGroup)
二:解决办法
1:网上常用的方法
<ListView android:id="@+id/lv_messages" android:layout_width="fill_parent" android:layout_height="fill_parent" > </ListView>
网上说执行多次原因是因为每显示一个VIew,它都去测量view的高度,执行measure方法,导致getView执行多次,但该listView嵌套在ScrollView时,BaseAdapter的getView()方法一样会调用多次。
2:重写ListView的onMeasure和onLayout方法。
我重写ListView的onMeasure和onLayout方法,定义一个,是否第一加载的变量boolean isOnMeasure=false,然后在BastAdapter的getView方法,判断是否第一次加载界面,通过这个方法来处理这个问题.
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { isOnMeasure = true; int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { isOnMeasure = false; super.onLayout(changed, l, t, r, b); }
三:完整代码
1:重写listView
public class ScrollListView extends ListView { private boolean isOnMeasure; public boolean isMeasure() { return isOnMeasure; } public ScrollListView(Context context) { super(context); } public ScrollListView(Context context, AttributeSet attrs) { super(context, attrs); } public ScrollListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { isOnMeasure = true; int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); // super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { isOnMeasure = false; super.onLayout(changed, l, t, r, b); } }
2:activity的xml
<view.ScrollListView android:id="@+id/orderGoodsList" style="@style/list_normal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@id/line3" android:background="@color/gray_f2" android:divider="@color/gray_f2" android:dividerHeight="1dip" > </view.ScrollListView>
3:适配器代码
protected ViewGroup viewGroup; @Override public void initData(View view, Object viewHolder, int position) { if (!((BaseGridView) viewGroup).isMeasure()) { //第一次加载,处理界面ui }else{ //不是第一次加载,不处理任何事 } }
如果你有更好的方法,也请你留下分享一下你的方法,谢谢!