BaseAdapter优化

转自:http://blog.csdn.net/yzx41099296/article/details/8100986

       当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。也就是说,如果让getCount()返回1,那么只显示一行。而getItem()和getItemId()则在需要处理和取得Adapter中的数据时调用。那么getView如何使用呢?如果有10000行数据,就绘制10000次?这肯定会极大的消耗资源,导致ListView滑动非常的慢。

public class MyListViewBase extends Activity {
    
    private ListView lv;
    //定义一个动态数组     
    ArrayList<HashMap<String, Object>>listItem;/** Called when the activity is first created. */ 
    
    @Override
    publicvoid onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        setupviews();
        //setuplistener(); 
        setupdata();       
        myadapter=new MyAdapter(this);
        listview.setAdapter(myadapter);
    }
	
	public void setupviews()
    	{
        sharebutton=(Button)findViewById(R.id.sharebutton);
        urlbutton=(Button)findViewById(R.id.urlbutton);
        httpbutton=(Button)findViewById(R.id.httpbutton);
        texturl=(TextView)findViewById(R.id.texturl);
        texthttp=(TextView)findViewById(R.id.texthttp);
        listview=(ListView)findViewById(R.id.listview);        
    	}
    
	/**添加一个得到数据的方法,方便使用*/ 
	public void setupdata()
	{
        	listItem = new ArrayList<HashMap<String,Object>>();    
		for(int i=0;i<30;i++)  
         	{  
			HashMap<String, Object> map = new HashMap<String, Object>();  
			map.put("Title", "第"+i+"行");  
			map.put("Text", "这是第"+i+"行");  
			listItem.add(map);  
		}        
	}        	
	
	public class MyAdapter extends BaseAdapter
	{
    		private LayoutInflater mInflater;
    		Context mContext;
    	
    		public MyAdapter(Context context)
    		{
    			mContext=context;
    			mInflater=LayoutInflater.from(mContext);
    		}
    	
		@Override
		public int getCount() {
			// TODO Auto-generated method stub
			return listItem.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) {
			// TODO Auto-generated method stub
			ViewHolder myholder;			
			if(convertView==null)
			{
				convertView=mInflater.inflate(R.layout.item,null);
				myholder=new ViewHolder();
				myholder.title=(TextView)convertView.findViewById(R.id.item1);
				myholder.text=(TextView)convertView.findViewById(R.id.item2);
				convertView.setTag(myholder);
				Log.v("yzx", "null getView " + position + " " + convertView);
			}
			else{
				myholder=(ViewHolder)convertView.getTag();
				Log.v("yzx", "getView " + position + " " + convertView);
			}
			myholder.title.setText(listItem.get(position).get("Title").toString());
			myholder.text.setText(listItem.get(position).get("Text").toString());
			return convertView;
		}    	
    }    
    public class ViewHolder
    {
    	public TextView title;
    	public TextView text;
    }

        convertView 在API中的解释是The old view to reuse, if possible, 第一次getView时还没有convertView,这时你便创建了一个新的view,下次getView时就有这个“旧的”convertView了 setTag的作用才是把查找的view通过ViewHolder封装好缓存起来方便多次重用,当需要时可以getTag拿出来
当你的listview里布局多样化的时候 viewholder的作用就有比较明显的体现了。 当然了,单一模式的布局一样有性能优化的作用 只是不直观。 假如你2种模式的布局 当发生回收的时候 你会用setTag分别记录是哪两种 这两种模式会被封装到viewholder中进行保存方便你下次使用。

        setTag方法是干什么的,他是给View对象的一个标签,标签可以是任何内容,我们这里把他设置成了一个对象,因为我们是把vlist2.xml的元素抽象出来成为一个类ViewHolder,用了setTag,这个标签就是ViewHolder实例化后对象的一个属性。我们之后对于ViewHolder实例化的对象holder的操作,都会因为java的引用机制而一直存活并改变convertView的内容,而不是每次都是去new一个。我们就这样达到的重用

 

       从图中可以看出,当启动Activity呈现第一屏ListView的时候,convertView为零。当用户向下滚动ListView时,上面的条目变为不可见,下面出现新的条目。这时候convertView不再为空,而是创建了一系列的convertView的值。当又往下滚一屏的时候,发现第11行的容器用来容纳第22行,第12行的容器用来容纳第23行。也就是说convertView相当于一个缓存,开始为0,当有条目变为不可见,它缓存了它的数据,后面再出来的条目只需要更新数据就可以了,这样大大节省了系统资料的开销

        还可以继续优化。虽然重复利用了已经绘制的view,但是要得到其中的控件,需要在控件的容器中通过findViewById的方法来获得。如果这个容器非常复杂,这显然会增加系统资源的开销。在上面的例子中,引入了Tag的概念。或许不是最好的办法,但是它确实能使ListView变得更流畅。代码中,当convertView为空时,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象。当convertView不为空,重复利用已经创建的view的时候,使用getTag()方法获取绑定的ViewHolder对象,这样就避免了findViewById对控件的层层查询,而是快速定位到控件。


        但是上面的仍然有缺陷,当我们的ListView中填充的item有多种形式时,比如微博中,有的item中包含图片,有的item包含视频,那么必然的,我们需要用到2种item的布局方式,此时如果只是单纯判断convert是否存在,会造成回收的view不符合你当前需要的布局,而类似转换失败出错退出
这里要提到Adapter中的另外2个方法:


public int getItemViewType(int position) {}
public int getViewTypeCount() {}

//每个convert view都会调用此方法,获得当前所需要的view样式
@Override
public int getItemViewType(int position) {
int p = position%6;
if(p == 0)
return TYPE_1;
else if(p < 3)
return TYPE_2;
else
return TYPE_1;
}
 
@Override
public int getViewTypeCount() {
return 2;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
viewHolder1 holder1 = null;
viewHolder2 holder2 = null;
int type = getItemViewType(position);
 
//无convertView,需要new出各个控件
if(convertView == null)
{
//按当前所需的样式,确定new的布局
switch(type)
{
case TYPE_1:
convertView = inflater.inflate(R.layout.listitem1, parent, false);
holder1 = new viewHolder1();
holder1.textView = (TextView)convertView.findViewById(R.id.textview1);
holder1.checkBox = (CheckBox)convertView.findViewById(R.id.checkbox);
convertView.setTag(holder1);
break;
case TYPE_2:
convertView = inflater.inflate(R.layout.listitem2, parent, false);
holder2 = new viewHolder2();
holder2.textView = (TextView)convertView.findViewById(R.id.textview2);
holder2.imageView = (ImageView)convertView.findViewById(R.id.imageview);
convertView.setTag(holder2);
break;
}
}
else
{
//有convertView,按样式,取得不用的布局
switch(type)
{
case TYPE_1:
holder1 = (viewHolder1) convertView.getTag();
break;
case TYPE_2:
holder2 = (viewHolder2) convertView.getTag();
break;
}
//设置资源
switch(type)
{
case TYPE_1:
holder1.textView.setText(Integer.toString(position));
holder1.checkBox.setChecked(true);
break;
case TYPE_2:
holder2.textView.setText(Integer.toString(position));
holder2.imageView.setBackgroundResource(R.drawable.icon);
break;
}
}
return convertView;
}
}
//各个布局的控件资源
class viewHolder1{
CheckBox checkBox;
TextView textView;
}
class viewHolder2{
ImageView imageView;
TextView textView;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值