android项目中如果使用listview控件,则在优化上我们一般使用viewHolder保证列表项的布局convertView可以被重用避免多次重新绘制。
- 一般方法中getView的写法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView =LayoutInflater.from(MainActivity.this).inflate(R.layout.item_listview, null);
viewHolder.numberTv = (TextView) convertView.findViewById(R.id.tv_no);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.numberTv.setText((String) listItemData.get(position).get("itemTitle"));
return convertView;
}
考虑这种情况,如果我们的列表的每一项中有很多控件则写相应的viewHolder比较麻烦,并且在每次写listview的时候都需要定义相应的viewHolder。因此考虑封装viewHolder。
优化的方法
- 自定义ViewHolder类
ViewHolder类
public class ViewHolder {
private Context mContext;
private View mConvertView;
private SparseArray<View> viewList;//在viewholder中用来存放列表项中的多个控件的数组
private ViewHolder(Context context, int layoutId, ViewGroup parentView) {
viewList = new SparseArray<View>();
mContext = context;
mConvertView = LayoutInflater.from(context).inflate(layoutId, parentView , false);
mConvertView.setTag(this);
}
private ViewHolder(Context mContext, int layoutId) {
viewList = new SparseArray<View>();
mConvertView = LayoutInflater.from(mContext).inflate(layoutId, null);
mConvertView.setTag(this);
}
/**
* 拿到一个viewholder对象
* @param context
* @param convertView
* @param layoutId
* @return ViewHolder
*/
public static ViewHolder get(Context context, View convertView, int layoutId ) {
if (convertView == null) {
return new ViewHolder(context, layoutId);
}
return (ViewHolder) convertView.getTag();
}
/**
* 得到当前列表项的布局
* @return
*/
public View getConvertView() {
return mConvertView;
}
/**
* 拿到列表项中的控件
* @param viewId
* @param <T>
* @return
*/
public <T extends View> T getView(int viewId) {
View childView = viewList.get(viewId);
if (childView == null) {//还未绑定列表项中的控件到viewholder中
childView = mConvertView.findViewById(viewId);
viewList.put(viewId, childView);
}
return (T) childView;
}
/**
* 设置文本
* @param viewId
* @param text
* @return ViewHolder 方便后续操作可多次调用该方法(连续点)
*/
public ViewHolder setText(int viewId, String text) {
TextView textView = getView(viewId);
textView.setText(text);
return this;
}
/**
* 设置textView的文本的颜色
* @param viewId
* @param color
*/
public ViewHolder setTextColor(int viewId, int color) {
TextView textView = getView(viewId);
textView.setTextColor(mContext.getResources().getColor(color));
return this;
}
/**
* 设置imageView的图像
* @param viewId
* @param drawableId
* @return ViewHolder
*/
public ViewHolder setImageResource(int viewId, int drawableId) {
ImageView imageView = getView(viewId);
imageView.setImageResource(drawableId);
return this;
}
/**
* 设置imageView的图像
* @param viewId
* @param drawableId
* @return
*/
public ViewHolder setImageBackground(int viewId, int drawableId) {
ImageView view = getView(viewId);
view.setBackgroundResource(drawableId);
return this;
}
/**
* 设置imageView的图像
* @param viewId
* @param bm
* @return
*/
public ViewHolder setImageBitmap(int viewId, Bitmap bm) {
ImageView view = getView(viewId);
view.setImageBitmap(bm);
return this;
}
}
要点分析:
为了避免每次都要自己定义相应的
viewHolder
声明列表项中对应每一项中的控件,使用sparseArray
稀疏数组来存放需要放在viewHolder
中的列表项中每一项中的view
。(文末有sparseArray
的简单介绍)在
viewHolder
类的构造方法中就用converView.setTag()
方法把viewHolder与列表项的布局的索引关系建立好,然后在viewHolder
中的get
方法得到viewHolder
对象。着重看看
getView
方法
/**
* 拿到列表项中的控件
* @param viewId
* @param <T>
* @return
*/
public <T extends View> T getView(int viewId) {
View childView = viewList.get(viewId);
if (childView == null) {//还未绑定列表项中的控件到viewholder中
childView = mConvertView.findViewById(viewId);
viewList.put(viewId, childView);
}
return (T) childView;
}
viewList
即是一个sparseArray
,通过键值对的方式存放列表每一项中的控件,之后就可以通过控件的id这个键来引用到对应的控件view了。
其他
在getView
方法后面的都是一些常用的通用方法方便使用可以自行扩展。2.在getView中使用方法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = ViewHolder.get(MainActivity.this, convertView, R.layout.item_listview);
viewHolder.setText(R.id.tv_no,(String)listItemData.get(position).get("itemTitle"));
return viewHolder.getConvertView();
}
特别提示:return viewHolder.getConvertView()
最后在getView方法中返回的convertView一定要是在ViewHolder中经过操作过的convertView
简单介绍一下sparseArray
这里简单的说明一下 sparseArray这个玩意。比较的去认识,官方拿这个与hashmap进行了比较。相对于hashmap,稀疏数组sparseArray可以节约内存。引用别人博客的例子来说明:
单纯从字面上来理解,SparseArray指的是稀疏数组(Sparse array) ,所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。
假设有一个9*7的数组,其内容如下:
一般的数组
在此数组中,共有63个空间,但却只使用了5个元素,造成58个元素空间的浪费。以下我们就使用稀疏数组重新来定义这个数组:
其中在稀疏数组中第一部分所记录的是原数组的列数和行数以及元素使用的个数、第二部分所记录的是原数组中元素的位置和内容。经过压缩之后,原来需要声明大小为63的数组,而使用压缩后,只需要声明大小为6*3的数组,仅需18个存储空间。
特别感谢,参考过的资料如下:
@linuxiao
sparseArray的介绍
android官方sparseArray介绍