Android ListView控件

使用ListView来展示数据需要以下三个元素:
1.Android提供的ListView的控件 —— 专门用来展示数据的界面
2.Adapter 适配器 —— 连接ListView和数据的桥梁
3.Data 数据 —— 需要在ListView上展示的数据

在以上三个元素中,Adpater起到了非常重要的作用,它把各种各样的数据抽象为统一的接口供ListView来使用。所以得名“适配器”。

列表的适配器一般分为三种: ArrayAdapter SimpleAdapter SimpleCursorAdapter, 其中以ArrayAdapter最为简单,只能展示一行字。SimpleAdapter有最好的扩充性,可以自定义出各种效果。SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方面的把数据库的内容以列表的形式展示出来。

一些较为简单的列表(比如ListView的每一项都是用做展示等等),以上的几种Adapter就完全足够用了,但是,如果ListView的某些项用来和用户交互,比如有可以点击的按钮,那么这时候上面的几种Adapter就不能满足我们的需要了,这时候我们必须从BaseAdapter派生出我们自己的Adapter来实现相应的功能。
具体的例子可以看该博客的内容:
点击查看链接

下面重点介绍关于ListView优化的一些知识。
1.使用getView()函数的参数ConvertView

getView方法里也提供了一个参数:convertView,这个参数代表着可以复用的view对象,当然这个对象也可能为空,当它为空的时候,表示该条目view第一次创建,所以我们需要inflate一个view出来,不为空时,直接复用:

@Override  
public View getView(int position, View convertView, ViewGroup parent) {   
   View view;   
   // 判断convertView的状态,来达到复用效果   
   if (null == convertView) {    
       //如果convertView为空,则表示第一次显示该条目,需要创建一个view    
       view = View.inflate(MainActivity.this, R.layout.listview_item,null);   
    } else {    
       //否则表示可以复用convertView    
       view = convertView;   
    }   
    // listview_item里只有一个textview   
    TextView tv_item = (TextView) view.findViewById(R.id.tv_item);     
    tv_item.setText(list.get(position));   
    return view;  
}

2.使用View Holder模式
上面的例子中,我们可以通过参数convertView来决定是不是需要inflate出来一个ItemView来达到优化的目的,但是呢,拿到convertView之后我们依然需要每次都通过函数findViewById()来查找对应的子控件,如果Layout布局比较复杂,那么这样的操作也会很耗时,所以可以从这里着手来进行进一步的优化:

private static class ViewHolder {  
   private TextView tvHolder; 
}

@Override  
public View getView(int position, View convertView, ViewGroup parent) {   
   View view;   
   ViewHolder holder;   
   // 判断convertView的状态,来达到复用效果   
   if (null == convertView) {    
       // 如果convertView为空,则表示第一次显示该条目,需要创建一个view    
       view = View.inflate(MainActivity.this, R.layout.listview_item, null);    
       //新建一个viewholder对象    
       holder = new ViewHolder();    
       //将findviewbyID的结果赋值给holder对应的成员变量    
       holder.tvHolder = (TextView) view.findViewById(R.id.tv_item);    
       // 将holder与view进行绑定    
       view.setTag(holder);   
    } else {    
       // 否则表示可以复用convertView    
       view = convertView;    
       holder = (ViewHolder) view.getTag();  
    }   
    // 直接操作holder中的成员变量即可,不需要每次都findViewById   
    holder.tvHolder.setText(list.get(position));   
    return view;  
}

这样,每次在新创建ItemView的时候,将View和持有View上的子控件的引用的ViewHolder进行绑定,当getView函数对以前的ItemView进行复用的时候,不需要再次用函数findViewById()进行查找了,而是直接用ViewHolder持有的引用进行操作就可以了,从而达到优化效率的目的。

3.一个优化后的、通用的Adapter的例子:

import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;

public abstract class MyAdapter<T> extends BaseAdapter {

    private ArrayList<T> mData;   // 界面上的数据
    private int mLayoutRes;       // item布局的资源id


    public MyAdapter() {
    }

    public MyAdapter(ArrayList<T> mData, int mLayoutRes) {
        this.mData = mData;
        this.mLayoutRes = mLayoutRes;
    }


    // 获取数据项的个数
    @Override
    public int getCount() {
        return mData != null ? mData.size() : 0;
    }

    // 获取数据项
    @Override
    public T getItem(int position) {
        return mData.get(position);
    }

    // 获取数据项的索引
    @Override
    public long getItemId(int position) {
        return position;
    }

    // 获取ItemView
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 拿到holder
        ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
                , position);
        // 数据与view相结合        
        bindView(holder, getItem(position));
        return holder.getItemView();
    }
    // 具体的绑定操作留给用户自己实现
    public abstract void bindView(ViewHolder holder, T obj);

    // 向数据集合中添加一个数据项
    public void add(T data) {
        if (mData == null) {
            mData = new ArrayList<>();
        }
        mData.add(data);
        // 刷新界面
        notifyDataSetChanged();
    }

    // 特定位置,插入元素
    public void add(int position, T data) {
        if (mData == null) {
            mData = new ArrayList<>();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }

    public void remove(T data) {
        if (mData != null) {
            mData.remove(data);
        }
        notifyDataSetChanged();
    }

    public void remove(int position) {
        if (mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }

    public void clear() {
        if (mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }

    // viewHolder类的实现
    public static class ViewHolder {

        private SparseArray<View> mViews;   // 缓存ListView中的Item上的所有子item
        private View item;                  // 该viewHolder所持有的item
        private int position;               // item所对应的位置
        private Context context;            // Context上下文

        //构造方法,完成相关初始化
        private ViewHolder(Context context, ViewGroup parent, int layoutRes) {
            mViews = new SparseArray<>();
            this.context = context;
            View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false);
            convertView.setTag(this);
            item = convertView;
        }

        //绑定ViewHolder与item
        public static ViewHolder bind(Context context, View convertView, ViewGroup parent,
                                      int layoutRes, int position) {
            ViewHolder holder;
            if (convertView == null) {
                holder = new ViewHolder(context, parent, layoutRes);
            } else {
                holder = (ViewHolder) convertView.getTag();
                holder.item = convertView;
            }
            holder.position = position;
            return holder;
        }

        // 获取Item上的子view,如果有缓存则直接返回,否则需要进行查找并缓存
        public <T extends View> T getView(int id) {
            T t = (T) mViews.get(id);
            if (t == null) {
                t = (T) item.findViewById(id);
                mViews.put(id, t);
            }
            return t;
        }


        // 获得当前持有的item
        public View getItemView() {
            return item;
        }

        // 获取索引号
        public int getItemPosition() {
            return position;
        }

        // 设置文字
        public ViewHolder setText(int id, CharSequence text) {
            View view = getView(id);
            if (view instanceof TextView) {
                ((TextView) view).setText(text);
            }
            return this;
        }

        // 设置图片
        public ViewHolder setImageResource(int id, int drawableRes) {
            View view = getView(id);
            if (view instanceof ImageView) {
                ((ImageView) view).setImageResource(drawableRes);
            } else {
                view.setBackgroundResource(drawableRes);
            }
            return this;
        }

        // 设置监听事件
        public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
            getView(id).setOnClickListener(listener);
            return this;
        }

        // 设置可见属性
        public ViewHolder setVisibility(int id, int visible) {
            getView(id).setVisibility(visible);
            return this;
        }
        // 设置标签
        public ViewHolder setTag(int id, Object obj) {
            getView(id).setTag(obj);
            return this;
        }
    }
}

使用的时候实现BindView函数定义具体的绑定操作:

//Adapter初始化
myAdapter1 = new MyAdapter<App>((ArrayList)mData1,R.layout.item_one) {
     @Override
     public void bindView(ViewHolder holder, App obj) {
            holder.setImageResource(R.id.img_icon,obj.getaIcon());
            holder.setText(R.id.txt_aname,obj.getaName());
            }
 };

//
RecyclerView也可以实现ListView的所有功能,但是功能比ListView要强大的多,详见博文

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值