当使用自定义Adapter来创建ListView时,注意以下几点,可以起到优化的作用:
在XML文件布局ListView时,android:layout_height不要定义为wrap_content,并且ListView的所有父节点布局的android:layout_height都不要定义为wrap_content。
正常情况下,一屏幕显示多少item,那么Adapter中的getView()函数会被调用几次。如果android:layout_height定义为wrap_content,那么getView()将被成倍调用。所以,建议使用fill_parent或者固定高度尺寸。
在getView()函数中,通过convertView != null的判断来复用convertView。
定义一个内部类ViewHolder,其中包含了item布局中的各个控件。
在初始化convertView时,也new一个ViewHolder,来保存convertView中的各个子控件。当复用convertView时,直接对相应的ViewHolder进行改动即可。避免convertView的findViewById()的耗时操作。
activity_demo_list.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
demo_list_item.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical">
<TextView
android:id="@+id/text"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textSize="20sp"
android:textColor="@android:color/background_dark"/>
public class DemoSimpleAdapter extends BaseAdapter {
private List<String> mData = new ArrayList<String>();
private Context mContext;
private LayoutInflater mFlater;
private static class ViewHolder {
public View bgView;
public TextView text;
}
public DemoSimpleAdapter(Context context, List<String> data){
this.mContext = context;
this.mData = data;
this.mFlater = LayoutInflater.from(mContext);
}
public void resetData(List<String> data){
this.mData = data;
this.notifyDataSetChanged();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mData.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mData.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder viewHolder = null;
if ( convertView == null ) {
convertView = mFlater.inflate(R.layout.demo_list_item,null);
viewHolder = new ViewHolder();
viewHolder.bgView = convertView;
viewHolder.text = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if( position%2 == 0 ) {
viewHolder.bgView.setBackgroundColor(Color.parseColor("#ffffff"));
} else {
viewHolder.bgView.setBackgroundColor(Color.parseColor("#f8fbd9"));
}
viewHolder.text.setText(mData.get(position));
return convertView;
}
}
4.分页加载:每次只加载固定数量的items,当滑动到ListView底部时,FooterView显示“正在加载”,加载其他数据。
<1>. 定义FooterView的布局:paging_load_list_footer.xml
<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="10dip"
android:paddingBottom="10dip"
android:background="@android:color/background_light"
android:orientation="horizontal"
android:gravity="center" >
<ProgressBar
android:id="@+id/pb_refresh"
android:layout_width="20dip"
android:layout_height="20dip"
style="@android:attr/progressBarStyleSmall" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:textSize="14sp"
android:textColor="@android:color/background_dark"
android:text="正在加载中..." />
<2>. 定义上拉刷新监听器OnFootLoadingListener。
public interface OnFootLoadingListener{
/**
* 这里是执行后台获取数据的过程
*/
void onFootLoading();
}
<3>. 定义实现分页加载功能的PagingLoadListView
public class PagingLoadListView extends ListView {
public int mDataTotalSize = 0; //数据集的全部条数
private int mVisibleLastIndex; //最后的可视项索引
private int mTotalItemCount; //ListView已经加载的数据项(如果有HeaderView,要-1。如果有FooterView,也要-1)。
private View mFooterView;
private boolean mIsFootLoading = false; //是否正在加载底部数据
private OnFootLoadingListener mFootLoadingListener = null;
public PagingLoadListView(Context context) {
super(context);
init();
}
public PagingLoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PagingLoadListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setOnFootLoadingListener(OnFootLoadingListener listener) {
mFootLoadingListener = listener;
}
public void onFootLoadingComplete(){
mIsFootLoading = false;
}
private void init() {
// 动态加载底部View
LayoutInflater flater = LayoutInflater.from(getContext());
mFooterView = flater.inflate(R.layout.paging_load_list_footer, null);
this.addFooterView(mFooterView);
// 设置透明背景
this.setCacheColorHint(0x00000000);
this.setOnScrollListener(new OnScrollListener(){
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
mVisibleLastIndex = getLastVisiblePosition();
mTotalItemCount = totalItemCount - 1; //要减去FooterView
if( mVisibleLastIndex == mTotalItemCount && mVisibleLastIndex != -1 && //滑动到底部
mDataTotalSize == mTotalItemCount ) { //全部数据都加载完了
ProgressBar pb = (ProgressBar) mFooterView.findViewById(R.id.pb_refresh);
pb.setVisibility(View.GONE);
TextView tv = (TextView) mFooterView.findViewById(R.id.tv_title);
if ( mDataTotalSize != 0 ) {
tv.setText("数据加载完毕");
} else {
tv.setText("没有数据");
}
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if( mIsFootLoading == false && scrollState == SCROLL_STATE_IDLE &&
mFootLoadingListener != null && mVisibleLastIndex > 0 &&
mVisibleLastIndex == mTotalItemCount && mVisibleLastIndex != mDataTotalSize ) {
//执行底部加载
mIsFootLoading = true;
mFootLoadingListener.onFootLoading();
}
}
});
}
}
<4>. 使用PagingLoadListView,设置OnFootLoadingListener,在回调函数中先重新加载数据,然后调用onFootLoadingComplete()。