安卓开发,listView相关(三),viewholder复用机制

时间:2021-04-24 22:43:29

1.复用(ViewHolder机制)介绍

之前我们使用了自定义适配器实现了安卓自带适配器实现的功能,流程为写一个类继承自BaseAdapter,重写四个方法,定义并初始化自定义适配器,调用listView的setAdapter()方法为listView绑定自定义适配器。 内容显示的过程为,显示一条内容即调用adapter的getView方法一次,可以在getView的第一行写一个log输出position即可验证。 那么当listView的数据过多的时候,例如1000条,而每一条的数据又极为复杂的时候,每调用一次getView方法就findviewById一次所有组件是极其损耗性能的。 为此提供了一个复用机制。ViewHolder。

1.1ViewHodler机制说明

每当listView的一条数据被滑出屏幕范围的时候,listView并不一定立即销毁该内容,而是保存下来,当下一次Adapter调用getView()方法的时候,这条数据就会被赋值给 getView方法中的第二个参数view上。那么通过获取view即可不必要再次findviewById,从而节省资源。 备注:至少有一条数据被滑出屏幕的时候,viewHolder才会起作用(即当listView的实际高度大于等于所有条目信息高度之和的时候,使用viewHolder并没有实际作用)

2.使用ViewHolder

写一个java类,可以把它单独写成一个文件,也可以直接放在adapter文件中,成为adapter的内部类
/***
* ViewHolder
* 在这里声明所有即在getView方法使用的组件
*/
class ViewHolder {
TextView tv;
Button bt;
}


为list_item.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="60dp">

<TextView
android:id="@+id/item_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />

<Button
android:id="@+id/item_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="点击" />
</RelativeLayout>

修改getView()方法中的代码:
/**
* 创建并返回每一条信息的实际内容
*
* @param position 当前创建并返回的是第几条信息
* @param view 当前布局内容,当前复用的布局
* @param viewGroup
* @return
*/
@Override
public View getView(final int position, View view, ViewGroup viewGroup) {
//声明ViewHolder
ViewHolder holder;
//当view为空的时候,说明当前行没有可以使用的复用信息,则创建一个
if (view == null) {
//加载刚才为适配器写的布局
view = inflater.inflate(R.layout.list_item, viewGroup, false);
//初始化viewHolder对象
holder = new ViewHolder();
//给组件赋值
holder.tv = (TextView) view.findViewById(R.id.item_textView);
holder.bt = (Button) view.findViewById(R.id.item_button);
//保存tag
view.setTag(holder);
}else //如果有可复用的信息,则直接获取
holder = (ViewHolder) view.getTag();
//根据数据源内容设置文本内容
holder.tv.setText(list.get(position));
holder.bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context,"点击"+position,Toast.LENGTH_SHORT).show();
}
});
//注意返回view,若返回null则上面的代码都不会生效
return view;
}

判断是否真的没有走if中的内容,可写log输出即可得到验证。 备注,之所以不用debug,因为这类测试debug起来异常麻烦,log则比较轻松,当然你也可以用syso 运行项目为:

安卓开发,listView相关(三),viewholder复用机制

3.其他说明

listView不会保存所有加载过的数据,当一些数据被滑出屏幕之外的时候,若没有因为复用而保存则会立即销毁。listView维护的始终只有屏幕显示的项和复用项。 实际维护的总大小总是小于等于屏幕显示项*2。 通过listView.getFirstVisiblePosition()和listView.getLastVisiblePosition()可以获取到当前屏幕显示的第一项和最后一项(根据实际滑动状态决定而不是固定的值)