ListView与BaseAdapter优化

  1. ListView使用BaseAdapter作适配器的时候,在初始化获取View或者滚动获取View时,都会调用getView方法返回View添加到ListView中,这也是ListView每一项的item。

     public View getView(int position, View convertView, ViewGroup parent)

    所传递的三个参数中,

    position表示所添加的view的位置,parent一般为listview。

    而convertView参数:

    1. 如果listView的layout_height设置为wrap_content时,除了position=0时convertView为null,其他时候convertView都不为空。(因为这样会疯狂调用getView方法,不推荐)

    2. 如果listView的layout_height设置为fill_parent或者指定高度时,当listView没有填充到所需高度时,每一个convertView都为null,后面都不为null。

      因为listView所需的全部view不可能全部加载到内存中,所以不需要显示的view就需要回收,回收的view即为convertView。
      以listview的高度为fill_parent为例:

    3. 当convertView为null时,每个item的View需要通过LayoutInflater实例化返回。

    4. 当convertView不为null时,如果整个listView的item使用的是一样的布局,那我们可以直接使用这个view,只需更新convertView中的数据即可。

  2. ViewHolder

    经常在文章中看到ViewHolder来优化ListView,但其实ViewHolder不是库函数,而是需要自己定义的类。(注意viewHolder里面item方法重绘:如invalidate,setVisiblity,requestLayout后,会调用adapter的getView方法

    使用ViewHolder的原因是findViewById方法耗时较大,如果控件个数过多,会严重影响性能,而使用ViewHolder主要是为了可以省去这个时间。通过setTag,getTag直接获取View。

     class  ViewHolder{
         ImageView img;
         TextView name;
     }
    
     public View getView(int position, View convertView, ViewGroup parent) {
         ViewHolder holder = null;
         if(convertView==null){
             convertView = inflater.inflate(R.layout.list_item, parent, false);
             holder.img = (ImageView) convertView.findViewById(R.id.img);
             holder.name = (TextView) convertView.findViewById(R.id.name);
             holder = new ViewHolder();
             convertView.setTag(holder);
         }else{
             holder = (ViewHolder) convertView.getTag();
         }
         //设置holder
         holder.img.setImageResource(R.drawable.ic_launcher);
         holder.name.setText(list.get(position).partname);
         return convertView;
     }
  3. OnScrollListener

    ListView经常需要展示图片,如果在滑动时对滑动过的每张图片都要加载,会比较占内存。推荐的优化方法是设置OnScrollListener,在滑动完成后再下载当前页面的图片。

     listView.setOnScrollListener(new AbsListView.OnScrollListener() {
         @Override
         public void onScrollStateChanged(AbsListView view, int scrollState) {
             switch (scrollState){
                 // 用户手指滑动中
                 case SCROLL_STATE_TOUCH_SCROLL:
                 // 用户手指离开,但滑动动画进行中
                 case SCROLL_STATE_FLING:
                     break;
                 // 滑动结束
                 case SCROLL_STATE_IDLE:
                     int start = listView.getFirstVisiblePosition();
                     int end = listView.getLastVisiblePosition();
                     if(end >= listView.getCount()){
                         end = listView.getCount() - 1;
                     }
                     //展示start-end之间的图片
                     break;
             }
         }
    
         @Override
         public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    
         }
     });
  4. onClickListener,当ListView的item中有比如button这些子view时,需要对其设置onclickListener,通常的写法是在getView方法中一个个设置,比如

     holder.img.setonClickListener(new onClickListenr)...

    但是这种写法每次调用getView时都设置了一个新的onClick事件,效率很低。高效的写法可以直接在ViewHolder中设置一个position,然后viewHolder implements OnClickListenr:

         class  ViewHolder implements OnClickListener{
             int position;
             TextView name;
    
             public void setPosition(int position){
                 this.position = position;
             }
    
             @Override
             public void onClick(View v) {
                 switch (v.getId()){
                     //XXXX
                 }
             }
         }
    
         public View getView(int position, View convertView, ViewGroup parent) {
             ViewHolder holder = null;
             if (convertView == null) {
                 convertView = inflater.inflate(R.layout.list_item, parent, false);
                 holder = new ViewHolder();
                 holder.name = (TextView) convertView.findViewById(R.id.name);
                 holder.name.setOnClickListener(holder);
                 convertView.setTag(holder);
             } else {
                 holder = (ViewHolder) convertView.getTag();
             }
             //设置holder
             holder.name.setText(list.get(position).partname);
             //设置position
             holder.setPosition(position);
             return convertView;
         }