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

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
运行项目为:


图片示例

3.其他说明

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


猜你喜欢

转载自blog.csdn.net/qq_26559913/article/details/53815611