代码中有注释:

使用方法:

1.可以在listview,gridview,stageView直接继承LazyAdapter使用

2.下面有Demo 代码

ViewHolder代码:

import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * holder处理的事情
 * 1.处理item的每个点击事件,具体业务由adapter来实现
 * 2.封装每个item的单一数据
 *
 * @param <T> T为当前item的单一数据
 */
public class SmartViewHolder<T> implements View.OnClickListener {
    //封装item的所有view
    private final SparseArray<View>   mViews      = new SparseArray<View>();
    private final SparseArray<Object> notifyFlags = new SparseArray<Object>();
    //当前item的数据
    private       T              currentData;
    private final LazyAdapter<T> adapter;
    private       View           mConvertView;

    private SmartViewHolder(Context context, ViewGroup parent, int layoutId, T currentData, LazyAdapter<T> adapter) {
        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        mConvertView.setTag(this);
        this.currentData = currentData;
        this.adapter = adapter;
    }

    public T getCurrentData() {
        return currentData;
    }

    public void setCurrentData(T currentData) {
        this.currentData = currentData;
    }

    /**
     * SmartViewHolder 单例操作
     *
     * @param context
     * @param convertView
     * @param currentData
     * @param parent
     * @param layoutId
     * @return holder instance
     */
    public static <T> SmartViewHolder<T> obtainHolder(Context context, View convertView, T currentData, ViewGroup parent, int layoutId, LazyAdapter<T> adapter) {

        if (convertView == null) {
            return new SmartViewHolder<T>(context, parent, layoutId, currentData, adapter);
        }
        SmartViewHolder<T> holder = (SmartViewHolder<T>) convertView.getTag();
        holder.currentData = currentData;
        return holder;
    }

    /**
     * 获取item指定view
     *
     * @param viewId view's id
     */
    public <V extends View> V getView(int viewId) {
        return getView(viewId, false);
    }

    /**
     * 获取item指定view
     *
     * @param viewId        view's id
     * @param hasClickEvent 如果该view不需要click事件 false
     */
    public <V extends View> V getView(int viewId, boolean hasClickEvent) {
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId, view);
            if (hasClickEvent) {
                view.setOnClickListener(this);
            }
        }
        return (V) view;
    }

    /**
     * 添加需要click的view
     * @param views  可变参数,view's id
     */
    public void requestClickEvent(int... views) {
        for (int item : views) {
            getView(item, true);
        }
    }

    @Override
    public void onClick(View v) {
        //回调holder指定view的click事件
        transferClickEvent(v, currentData);
    }

    /**
     * 回调holder的点击事件,具体业务实现在adapter
     * @param view
     * @param currentData
     */
    private void transferClickEvent(View view, T currentData) {
        adapter.handleClick(this, view, currentData);
    }

    /**
     * @return rootView
     */
    public View getConvertView() {
        return mConvertView;
    }

    /**
     * 1.数据显示完成后,用holder记住view正在显示的数据,
     * 下次notify时,如果数据没有变化,则不用再次显示
     * 2.如果该view的数据发生变化,则需要调用updateShowingData()更新变化的数据
     *
     * @param view
     * @param data
     * @return
     */
    public boolean showingDataChanged(View view, Object data) {
        return !(notifyFlags.get(view.getId()) != null &&
                 notifyFlags.get(view.getId()).equals(data));
    }

    /**
     * 如果该view的数据发生变化,则需要调用该方法来更新变化的数据
     *
     * @param view
     * @param data
     */
    public void updateShowingData(View view, Object data) {
        notifyFlags.put(view.getId(), data);
    }

    public Object getShowingData(View view) {
        return notifyFlags.get(view.getId());
    }
}

adapter代码:添加了增删的方法

package com.smart_holder_lib;

import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

/**
 * @param <T> T为当前Item数据
 * @author Relice
 */
public abstract class LazyAdapter<T> extends BaseAdapter {
    private static final String TAG = LazyAdapter.class.getSimpleName();
    protected Context mContext;
    //设置数据
    private final List<T>    dataSet       = new ArrayList<T>();
    //被选中要删除的数据
    public final HashSet<T> removeDataSet = new HashSet<T>();
    // adapter的item布局
    private int mItemLayoutId;
    //checkBox选中的数据
    private T   removeData;
    private List<T> datas;//传过来的数据

    /**
     * 调用该方法你需要传入以下数据
     * @param context
     * @param datas   列表需要显示的数据集合
     * @param mItemLayoutId item布局
     */
    public LazyAdapter(Context context, List<T> datas, int mItemLayoutId) {
        this.mContext = context;
        this.datas = datas;
        this.mItemLayoutId = mItemLayoutId;
        setDatas(datas);
    }

    @Override
    public int getCount() {
        return dataSet.size();
    }

    @Override
    public T getItem(int position) {
        if (position > -1 && position < dataSet.size()) {
            return dataSet.get(position);
        }
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        T currentData = getItem(position);
        //holder处理的事情
        //1.处理item的每个点击事件
        //2.封装每个item的单一数据
        SmartViewHolder<T> viewHolder = SmartViewHolder.obtainHolder(mContext, convertView, currentData, parent, mItemLayoutId, this);
        //显示holder填好数据的item --    show UI
        showDataInItemView(viewHolder, currentData);
        return viewHolder.getConvertView();
    }

    /**
     * 覆盖此方法来显示UI
     *
     * @param viewHolder  holder ,使用他来操作view的一些逻辑事件
     * @param currentData 当前item的数据
     */
    protected abstract void showDataInItemView(SmartViewHolder<T> viewHolder, T currentData);

    /**
     * 覆盖此方法来处理点击事件,如果当前item没有任何点击事件,直接空实现即可
     *
     * @param convertView item view
     * @param view        clicked view
     * @param currentData data of current item
     */
    protected abstract void handleClick(SmartViewHolder<T> convertView, View view, T currentData);

    /**
     * 重置所有数据
     */
    public void setDatas(List<T> datas) {
        if (datas == null) {
            return;
        }
        Log.d(TAG, "setDatas " + datas.size());
        this.dataSet.clear();
        this.dataSet.addAll(datas);
        notifyDataSetChanged();
    }

    /**
     * 重置单个数据
     */
    public void setData(T data) {
        if (data == null) {
            return;
        }
        dataSet.clear();
        dataSet.add(data);
    }

    /**
     * 加载更多时-添加数据
     *
     * @param datas
     * @param filterData
     */
    public void addDatas(List<T> datas, boolean filterData) {
        if (datas == null) {
            return;
        }
        if (filterData) {
            this.dataSet.removeAll(datas);
        }
        this.dataSet.addAll(datas);
        notifyDataSetChanged();
    }

    /**
     * 加载更多时-添加数据
     *
     * @param datas
     */
    public void addDatas(List<T> datas) {
        addDatas(datas, false);
    }

    /**
     * 加载更多时-添加数据
     *
     * @param data
     */
    public void addData(T data) {
        if (data == null || dataSet.contains(data)) {
            return;
        }
        dataSet.add(data);
        notifyDataSetChanged();
    }

    /**
     * 添加要删除的数据--批量添加
     *
     * @param removeData
     */
    public void addRemoveData(T removeData) {
        if (removeData != null) {
            removeDataSet.add(removeData);
        }
    }

    /**
     * 移除被添加的数据
     *
     * @param removeData
     */
    public void removeAddedData(T removeData) {
        if (removeData != null) {
            removeDataSet.remove(removeData);
        }
    }

    /**
     * 批量删除添被加了数据,
     * 一般用于activity回调adapter刷新数据
     */
    public void removeAllData() {
        if (removeDataSet == null) {
            return;
        }
        for (Iterator it = removeDataSet.iterator(); it.hasNext(); ) {
            T next = (T) it.next();
            if (next == null) {
                continue;
            }
            this.dataSet.remove(next);
            this.datas.remove(next);//TODO 删除传过来的数据
            it.remove();
        }
        notifyDataSetChanged();
    }
}

Demo使用:

下面只给了主要代码;部分helper,utils 工具类没贴出来

import android.app.Activity;
import android.content.Intent;
import android.text.TextUtils;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.smart_holder_lib.LazyAdapter;
import com.smart_holder_lib.SmartViewHolder;

import java.util.List;

/**
 * 我的关注-品牌列表
 * 优化处理
 *
 * @author Relice
 */
public class MyXiuNewCollectionBrandAdapter extends LazyAdapter<BrandInfo> {
    private Activity activity;
    private Utils    util;
    private int      index;

    public void setIndex(int index) {
        this.index = index;
    }

    public MyXiuNewCollectionBrandAdapter(Activity activity, List<BrandInfo> list, int index, int layoutId) {
        super(activity, list, layoutId);
        this.activity = activity;
        util = Utils.getInstance();
        this.index = index;
    }

    @Override
    protected void showDataInItemView(SmartViewHolder<BrandInfo> holder, BrandInfo brandInfo) {
        ImageView my_collection_brand_iv = holder.getView(R.id.my_collection_brand_iv, false);
        TextView my_collection_brand_tv = holder.getView(R.id.my_collection_brand_tv, false);
        TextView my_collection_brandname = holder.getView(R.id.my_collection_brandname, false);
        TextView my_collection_brandchosen = holder.getView(R.id.my_collection_brandchosen, false);//精选卖场TV
        CheckBox my_collection_delbranditem_cb = holder.getView(R.id.my_collection_delbranditem_cb, true);//勾选删除
        RelativeLayout my_collection_right_layouttop = holder.getView(R.id.my_collection_right_layouttop, true);//新品上架
        RelativeLayout my_collection_right_layoutbuttom = holder.getView(R.id.my_collection_right_layoutbuttom, true);//精选卖场
        LinearLayout collect_brand_logo_layout = holder.getView(R.id.collect_brand_logo_layout, true);//品牌logo卖场
        //是否需要删除
        my_collection_delbranditem_cb.setChecked(brandInfo.isDelItem());

        //品牌图片
        final boolean hasImage = !TextUtils.isEmpty(brandInfo.getBrandImg());
        if (hasImage) {
            //数据显示完成后,用holder记住view正在显示的数据,下次notify时,如果数据没有变化,则不用再次显示
            if (holder.showingDataChanged(my_collection_brand_iv, brandInfo.getBrandImg())) {
                util.loadBrandCollectImage(activity, my_collection_brand_iv, brandInfo.getBrandImg());
                holder.updateShowingData(my_collection_brand_iv, brandInfo.getBrandImg());
                SHelper.vis(my_collection_brand_iv);
                SHelper.gone(my_collection_brand_tv);
            }
        } else {//没有图片显示品牌名
            SHelper.vis(my_collection_brand_tv);
            SHelper.gone(my_collection_brand_iv);
            my_collection_brand_tv.setText(brandInfo.getBrandName());
        }

        //品牌名
        String brandName = brandInfo.getBrandName();
        if (holder.showingDataChanged(my_collection_brandname, brandName)) {
            //            数据显示完成后,用holder记住view正在显示的数据,下次notify时,如果数据没有变化,则不用再次显示
            my_collection_brandname.setText(brandName);
            holder.updateShowingData(my_collection_brandname, brandName);
        } else {
            //            SLog.dd("复用数据..");
        }

        //编辑/完成
        if (index == 1) {
            SHelper.vis(my_collection_delbranditem_cb);
        } else {
            SHelper.gone(my_collection_delbranditem_cb);
        }

        //处理编辑状态点击
        handleEdietStatus(my_collection_delbranditem_cb, my_collection_right_layoutbuttom, my_collection_right_layouttop, collect_brand_logo_layout);

        //卖场活动是否结束
        final int topicCnt = brandInfo.getTopicCnt();
        if (topicCnt == 0) {
            my_collection_right_layoutbuttom.setEnabled(false);
            my_collection_brandchosen.setTextColor(activity.getResources().getColor(R.color.xiu_grey));
        } else {
            my_collection_brandchosen.setTextColor(activity.getResources().getColor(R.color.xiu_black));
//            my_collection_right_layoutbuttom.setEnabled(true);
        }
    }

    private void handleEdietStatus(CheckBox cb, View... view) {
        boolean clickAble = true;
        if (cb != null && cb.getVisibility() == View.VISIBLE)
            clickAble = false;
        else
            clickAble = true;

        for (int i = 0; i < view.length; i++) {
                view[i].setEnabled(clickAble);
        }
    }

    @Override
    protected void handleClick(SmartViewHolder<BrandInfo> convertView, View view, BrandInfo brandInfo) {
        switch (view.getId()) {
            case R.id.my_collection_right_layouttop://新品上架
                activity.startActivity(new Intent(activity, BrandGoodsListActivity.class).putExtra("brand_id",
                        brandInfo.getBrandId() +
                        "").putExtra("brand_name", brandInfo.getBrandName()).putExtra("brand_img", brandInfo.getBrandImg()).putExtra("brand_tag", 3).putExtra("goodsFrom", "UC0040"));
                break;
            case R.id.my_collection_right_layoutbuttom://精选卖场
                final int topicCnt = brandInfo.getTopicCnt();
                if (topicCnt == 1) {
                    activity.startActivity(new Intent(activity, GoodsListActivity.class).
                            putExtra("activity_id", brandInfo.getActivityId()).putExtra("activity_name", brandInfo.getBrandName()).putExtra("activity_img", brandInfo.getBrandImg()).
                            putExtra("goodsFrom", "UC0040"));
                } else {
                    activity.startActivity(new Intent(activity, SelectStoresActivity.class).
                            putExtra("brand_name", brandInfo.getBrandName()).putExtra("brand_id", brandInfo.getBrandId()).putExtra("goodsFrom", "UC0040"));
                }
                break;
            case R.id.collect_brand_logo_layout: //品牌logo卖场
                activity.startActivity(new Intent(activity, BrandGoodsListActivity.class).putExtra("brand_id",
                        brandInfo.getBrandId() +
                        "").putExtra("brand_name", brandInfo.getBrandName()).putExtra("brand_img", brandInfo.getBrandImg()).putExtra("goodsFrom", "UC0040"));
                break;
            case R.id.my_collection_delbranditem_cb: //勾选要删除的品牌

                CheckBox cb = (CheckBox) view.findViewById(R.id.my_collection_delbranditem_cb);
                boolean checked = cb.isChecked();
                if (checked) {
                    brandInfo.setIsDelItem(true);
                    addRemoveData(brandInfo);//添加删除
                } else {
                    brandInfo.setIsDelItem(false);
                    removeAddedData(brandInfo);//取消删除
                }
                break;
        }
    }
}

一个优化极点的ViewHolder的更多相关文章

  1. ListView性能优化——convertView&viewHolder

    ListView优化大致从以下几个角度:1.复用已经生成的convertView:2.添加viewHolder类:3.缓存数据(图片缓存):4.分页加载. 具体方案: 1.如果自定义适配器,那么在ge ...

  2. ListView优化的时候ViewHolder的简洁写法

    在ListVIew做复用优化的时候,经常会写ViewHolder,还需要很麻烦的去findview,我最讨厌写一堆的这样代码了,今天看到了一个极简的写法,很好用,很简洁啊!!! public stat ...

  3. MySQL order by的一个优化思路

    最近遇到一条SQL线上执行超过5s,这显然无法忍受了,必须要优化了. 首先看眼库表结构和SQL语句. CREATE TABLE `xxxxx` ( `id` ) NOT NULL AUTO_INCRE ...

  4. 《转》Unity3D研究院之UGUI一个优化效率小技巧

    无意间发现了一个小技巧.如下图所示,可以发现UGUI的Image组件的RaycastTarget勾选以后会消耗一些效率,为了节省效率就不要勾选它了,不仅Image组件Text组件也有这样的问题. 一般 ...

  5. Unity教程之-UGUI一个优化效率小技巧

    无意间发现了一个小技巧.如下图所示,可以发现UGUI的Image组件的RaycastTarget勾选以后会消耗一些效率,为了节省效率就不要勾选它了,不仅Image组件Text组件也有这样的问题. 一般 ...

  6. 大流量网站性能优化:一步一步打造一个适合自己的BigRender插件

    BigRender 当一个网站越来越庞大,加载速度越来越慢的时候,开发者们不得不对其进行优化,谁愿意访问一个需要等待 10 秒,20 秒才能出现的网页呢? 常见的也是相对简单易行的一个优化方案是 图片 ...

  7. VS编译器优化诱发一个的Bug

    VS编译器优化诱发一个的Bug Bug的背景 我正在把某个C++下的驱动程序移植到C下,前几天发生了一个比较诡异的问题. 驱动程序有一个bug,但是这个bug只能 Win32 Release 版本下的 ...

  8. Android数据适配器(Adapter)优化:使用高效的ViewHolder

    原文链接:http://stackvoid.com/using-adapter-in-efficiency-way/ 在使用Listview或GridView的时候,往往须要自己定义数据适配器.一般都 ...

  9. 从Linux 2.6.8内核的一个TSO/NAT bug引出的网络问题排查观点(附一个skb的优化点)

    梦中没有错与对,梦中没有恨和悔...最好闭上你的嘴.这样才算可爱...我不会说:这不公道,我不能接受.我会用朴素的文字记录点点滴滴,早上4点多起来,一气呵成最近的收获与评价,愤慨与忏悔. 四年多前的一 ...

随机推荐

  1. logistic分类

    对Logistic回归模型,个人做的一些总结: 公式就不套用了,教材上面基本都有而且详细.logistic回归用图形化形式描述如下: logistic回归是一种简单高效的分类模型,它不仅可以通过学习来 ...

  2. 关于前端HTML你需要知道的一切

    1.H系列标签(Header 1~Header 6) 作用: 用于给文本添加标题语义 格式: <h1>xxxxxx</h1> 注意点: H标签是用来给文本添加标题语义的, 而不 ...

  3. MT8127:如何让system分区可读写(MTK安卓6.0)

    Android 系统默认情况下,system 分区是只读 mount 的,因为无法进行往里写数据的,可 以用 adb 命令 adb remount 重新 mount 一下. 也可以通过在板子上,输入以 ...

  4. Leetcode解题-树(5.0.0)基础类

    与第二章类似,LeetCode指定了TreeNode实现.为了方便后续习题的编写和测试,创建一个基础父类,包含TreeNode实现,以及create()和print()创建和打印树的方法.其中crea ...

  5. maven配置详解

    什么是pom?     pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者需要遵循的规则,缺陷管理系统,组织和licenses,项目的 ...

  6. Ajax框架,DWR介绍,应用,例子

    使用Ajax框架 1. 简化JavaScript的开发难度 2. 解决浏览器的兼容性问题 3. 简化开发流程 常用Ajax框架 Prototype 一个纯粹的JavaScript函数库,对Ajax提供 ...

  7. 如何将Provisioning Profile安装到开发的Mac系统上

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...

  8. FFmpeg的H.264解码器源代码简单分析:解码器主干部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  9. Microsoft Dynamics CRM2011 更换Logo

    之前操作过但没做过记录,这里记录下以防以后有需要时记不起来还有迹可循 IE收藏栏的图标,在网站根目录下的的/favicon.ico CRM网页中的Logo,替换/_imgs/crmmastheadlo ...

  10. Hibernate 缓存机制全面讲解

    简介 为了降低应用程序访问我们的数据的时候的频率,提高数据读取的速率.比如计算机中为了缓解CPU和内存之间速度差异而引入的缓存是一样的道理.Hibernate同样对缓存进行了支持,使得程序的运行效率得 ...