您的位置:首页 > 移动开发 > Android开发

Android关于ListView的优化

2015-01-13 00:00 267 查看
摘要: 优化ListView的3个小技巧

当使用自定义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

<?xml version="1.0" encoding="UTF-8"?>
<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"/>
</LinearLayout>

demo_list_item.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"/>
</LinearLayout>

public class DemoSimpleAdapter extends BaseAdapter {
private List<String> mData = new ArrayList<String>();
private Context mContext;
private LayoutInflater mFlater;
private ViewHolder viewHolder = null;

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();
}

// 调用notifyDataSetChanged()将重绘整个可见的ListView
// 下面自定义函数,只重绘position所在的某一项item:
public boolean notifyDataSetChanged(int position, ListView listView) {
boolean updated = false;
int firstVisiblePosition = listView.getFirstVisiblePosition();
int lastVisiblePosition = listView.getLastVisiblePosition();
if ( position >= firstVisiblePosition && position <= lastVisiblePosition ) {
View v = listView.getChildAt(position - firstVisiblePosition);
if ( v != null ) {
View layout = v.getContentView();
ViewCache holder = (ViewCache) layout.getTag();
if ( holder != null ) {
resetViewCacheHolder(position, holder);
updated = true;
}
}
}
return updated;
}

@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

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();
}
resetViewCacheHolder(position, viewCache);
return convertView;
}

private void resetViewCacheHolder(int position, ViewHolder holder) {
if( position%2 == 0 ) {
holder.bgView.setBackgroundColor(Color.parseColor("#ffffff"));
} else {
holder.bgView.setBackgroundColor(Color.parseColor("#f8fbd9"));
}
holder.text.setText(mData.get(position));
}

}

更多参考:http://mobile.51cto.com/abased-445617.htm

4.分页加载:每次只加载固定数量的items,当滑动到ListView底部时,FooterView显示“正在加载”,加载其他数据。

<1>. 定义FooterView的布局:paging_load_list_footer.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="正在加载中..." />
</LinearLayout>

<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()。

5.ScrollView嵌套ListView只显示一行的解决方案:
<1>. 重写ListView:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}

<2>. 重新计算ListView的高度,解决ScrollView和ListView两个View都有滚动的效果,在嵌套使用时起冲突的问题,设置scrollView中的ListView内容全部显示,不能滑动,将滑动交给scrollView去做.
注意:ListView的每个Item必须是LinearLayout,在设置ListView的Adapter后调用此方法,并且ListView的高度要指定,这样才能重新计算,不要设成wrapcontent.

public static void setListViewHeightBasedOnChildren(ListView listView) {
if(listView == null) return;
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}

int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
int desiredWidth = MeasureSpec.makeMeasureSpec(
listView.getWidth(), MeasureSpec.AT_MOST);
listItem.measure(desiredWidth, 0);
totalHeight += listItem.getMeasuredHeight();
}

ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  优化ListView