Android开发之ListView中Adapter的优化

    ListView是Android开发最常用的控件,适配器adapter是将要显示的数据映射到View中并添加到ListView中显示
在实现ListView时,我们需要定义适配器如BaseAdapter、ArrayAdapter、CursorAdapter、SimpleAdapter等,并且重写其一下四个方法:
     1 public int getCount();
     2 public Object getItem(int position) 
     3  public long getItemId(int position)
     4 public View getView(int position, View convertView, ViewGroup parent)


我们需要定义一个View,用来显示每条信息,最后添加到ListView中。

比如我们定义了一个view文件:list_item_callsms.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:layout_marginTop="3dip"
        android:layout_marginLeft="10dip"
        android:id="@+id/tv_black_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="黑名单号码"
        android:textColor="#88000000"
        android:textSize="20sp" />

    <TextView
        android:layout_marginTop="3dip"
        android:layout_marginLeft="10dip"
        android:id="@+id/tv_black_mode"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/tv_black_number"
        android:text="拦截模式"
        android:textColor="#88000000"
        android:textSize="15sp" />

</RelativeLayout>


我们在实现Adapter时,假设我们这样操作:

private List<BlackNumberInfo> infos;

private class CallSMSSafeAdapter extends BaseAdapter {

		@Override
		public int getCount() {
			// 返回多少条
			return infos.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return 0;
		}

		//有多少个条目    这个方法就会被调用多少次
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			//把一个布局文件转换成一个  view对象    每次都要调用  非常占用内存空间
			View view = View.inflate(getApplicationContext(),
					R.layout.list_item_callsms, null);
			TextView tv_black_number = (TextView) view
					.findViewById(R.id.tv_black_number);
			TextView tv_black_mode = (TextView) view
					.findViewById(R.id.tv_black_mode);

			tv_black_number.setText(infos.get(position).getNumber());
			String mode = "全部拦截";
			if (infos.get(position).getMode().equals("1")) {
				mode = "电话拦截";
			} else if (infos.get(position).getMode().equals("2")) {
				mode = "短信拦截";
			}

			tv_black_mode.setText(mode);
			return view;
		}

	}

上面会出现一个问题,当要显示的数据集合超过100多条时(infos),当我们快速的滑动ListView时,界面会显示程序无响应,而LogCat中则不停的打印DVM虚拟机GC垃圾回收数据(实际是每次定义的View对象);这样别然严重的影响程序的性能和用户体验;


所以针对上述,可以对ListView使用的Adapter做两方面的优化:

      1、 减少内存中View对象的创建次数个数。

             ListView中的View在第一个可见的列表里是创建的(converView是为null的),当再次加载滑动时,会converView会复用之间创建的view,之后循环这个可见的View对象列表。

            

convertView The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).

      2、减小view中对应控件查找的次数。

            每次查找view中的控件都是相当耗时的,相当于遍历了一遍view对应的xml树,所以我们只需在第一个遍历,以后直接复用。

            因此我们可以创建一个View缓存,然后使用view的Tag存放的控件在内存中的地址。所以我们最多创建ViewList可见的长度个View,查找一次View中控件的id。

这样就能很大的提升程序的性能。


优化后的代码如下:

private class CallSMSSafeAdapter extends BaseAdapter {

		@Override
		public int getCount() {
			// 返回多少条
			return infos.size();
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return 0;
		}

		//有多少个条目    这个方法就会被调用多少次
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			
			ViewHolder holder = null;
			
			//把一个布局文件转换成一个  view对象    每次都要调用  非常占用内存空间
			//1. 减小内存中View对象创建的个数
			if(convertView == null){
				//converView 为空时 才创建
				convertView = View.inflate(getApplicationContext(),
						R.layout.list_item_callsms, null);
				holder = new ViewHolder();
				//2. 减小View中控件查询的次数 
				holder.tv_number = (TextView) convertView
						.findViewById(R.id.tv_black_number);
				holder.tv_mode = (TextView) convertView
						.findViewById(R.id.tv_black_mode);
				//把ViewHolder保存在View的tag中
				convertView.setTag(holder);
				
			}else {
				//获取View的Tag中的ViewHolder
				holder = (ViewHolder) convertView.getTag();
			}
			
			

			holder.tv_number.setText(infos.get(position).getNumber());
			String mode = "全部拦截";
			if (infos.get(position).getMode().equals("1")) {
				mode = "电话拦截";
			} else if (infos.get(position).getMode().equals("2")) {
				mode = "短信拦截";
			}

			holder.tv_mode.setText(mode);
			return convertView;
		}

	}
	
	/**
	 * 记录View中控件的内存地址  相当于一个记事本
	 * @author zty
	 *
	 */
	static class ViewHolder{
		TextView tv_number;
		TextView tv_mode;
	}





郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。