• Android BaseAdapter和ViewHolder 优化 解决ListView的item抢焦点问题和item错乱问题


    首先赞下hyman大神

    曾经仅仅是简单的重写个BaseAdapter,将getView方法保持抽象。而ViewHolder没有抽象过。

    。。


    ViewHolder (用了一个集合+泛型管理存取view)

    /**
     * author : stone
     * email  : aa86799@163.com
     * time   : 15/7/24 14 27
     */
    public class StoneViewHolder {
    
        private int mPosition;
        private View mConvertView;
        private SparseArray<View> mViews;  //管理listView-item中的view
    
        public StoneViewHolder(Context context, int layoutId, int position, ViewGroup parent) {
            this.mPosition = position;
    
            this.mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
            this.mConvertView.setTag(this);
    
            this.mViews = new SparseArray<View>();
        }
    
        public View getConvertView() {
            return mConvertView;
        }
    
        public static StoneViewHolder getInstance(Context context, int layoutId, int position, View
                convertView, ViewGroup parent) {
            if (convertView == null) {
                return new StoneViewHolder(context, layoutId, position, parent);
            } else {
                StoneViewHolder holder = (StoneViewHolder) convertView.getTag();
                holder.mPosition = position;  //更新复用的convertView中  position
                return holder;
            }
        }
    
        public <T extends View>  T getView(int viewId) {
            View view = mViews.get(viewId);
            if (view == null) {
                view = mConvertView.findViewById(viewId);
                mViews.put(viewId, view);
            }
            return (T) view;
        }
    
        public <T> void setTag(int viewId, T tag) {
            getView(viewId).setTag(tag);
        }
    
        public <T> T getTag(int viewId) {
            return (T) getView(viewId).getTag();
        }
    
        /*------------------------  设置view属性(以后扩展) --------------------------------*/
    
        public StoneViewHolder setText(int viewId, String text) {
            ((TextView)getView(viewId)).setText(text);
            return this;
        }
    
        public StoneViewHolder setText(int viewId, int resId) {//R.string.
            ((TextView)getView(viewId)).setText(resId);
            return this;
        }
    
        public StoneViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
            ((ImageView)getView(viewId)).setImageBitmap(bitmap);
            return this;
        }
    
        public StoneViewHolder setImageResource(int viewId, int resId) {
            ((ImageView)getView(viewId)).setImageResource(resId);
            return this;
        }
    }

    Adapter

    /**
     * author : stone
     * email  : aa86799@163.com
     * time   : 15/7/24 14 46
     */
    public abstract class StoneListAdapter<T> extends BaseAdapter {
    
        private List<T> mData;
        private Context mContext;
        private int mLayoutID;
    
        public StoneListAdapter(Context context, int layoutID, List<T> data) {
            this.mContext = context;
            this.mLayoutID = layoutID;
            this.mData = data == null ? new ArrayList<T>() : data;
        }
    
        @Override
        public int getCount() {
            return mData.size();
        }
    
        @Override
        public T getItem(int position) {
            return mData.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            StoneViewHolder holder = StoneViewHolder.getInstance(mContext, mLayoutID, position,
                    convertView, parent);
    
            getView(mContext, holder, position);
    
    
            return holder.getConvertView();
        }
    
        protected abstract void getView(Context context, StoneViewHolder holder, int position);
    
    }
    

    在ListViewActivity中使用

    stoneBaseAdapter = new StoneListAdapter<User>(ListViewActivity.this, R.layout.activity_listview_item, mData) {
    
        @Override
        protected void getView(Context context, final StoneViewHolder holder, final int position) {
            User user = getItem(position);
    
            holder.setText(R.id.tv_id, user.getId()).setText(R.id.tv_name, user.getName())
                    .setText(R.id.tv_age, user.getAge() + "");
    
            holder.getView(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                }
            });
    
        }
    };


    关于Adapter中View抢焦点

     假设 listView.setOnItemClickListener(listener);   且item中的  button.setOnClickListener(listener); 

     无论怎么点击,button会一直被触发...

     仅仅须要在item的root-layout中 加入 一个属性:   android:descendantFocusability="blocksDescendants"


    关于item-view复用后。显示混乱:

    有时条目过多,滑动到下一屏数据时。有些view复用后,view的状态(比方CheckBox的选种状态。ImageView的图片反复出现)会变乱。

    一般处理呢。须要有一个机制,来管理一种相应关系: 当前position相应哪种状态

    比方说checkBox选中状态混乱:

       

    class MyAdapter extends StoneListAdapter<User> {
            private SparseBooleanArray mCheckStateArray;
    
            public MyAdapter(Context context, int layoutID, List data) {
                super(context, layoutID, data);
                this.mCheckStateArray = new SparseBooleanArray();
            }
    
            public void setChecked(int position, boolean isChecked) {
                mCheckStateArray.put(position, isChecked);
            }
    
            public boolean isChecked(int position) {
                return mCheckStateArray.get(position);
            }
    
            @Override
            protected void getView(Context context, final StoneViewHolder holder, final int position) {
                
                CheckBox cb = holder.getView(R.id.cb_check);
                cb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        setChecked(position, isChecked);//记录状态。防缓存显示
                    }
                });
                cb.setChecked(isChecked(position));
            }
        }

    关于SparseArray

     SparseArray 内部实现是Array数组。当长度不够时,会调用System.arrayCopy
            内部有 keys和values两个数组。


            put(key, value); 二分法查找key应该存放的位置  由于key是Integer类型
            put、get时 两个数组都是操作的同一个位置上的数据


        SparseArray 用于替代形如  HashMap<Integer, Object>
        SparseBooleanArray 用于替代形如  HashMap<Integer, Boolean>
        SparseIntArray 用于替代形如  HashMap<Integer, Integer>
        SparseLongArray 用于替代形如  HashMap<Integer, Long>

      support.v4.util.SparseArrayCompat 提供了v4包相应平台的 SparseArray实现


  • 相关阅读:
    sizeof与strlen的区别
    面试题46:求1+2+...+n
    opennebula 安装指定参数
    opennebula 开发记录
    virsh 查看hypervisor特性
    opennebula kvm日志
    Cgroup
    opennebula kvm 创建VM oned报错日志
    opennebula kvm 创建虚拟机错误
    golang hello
  • 原文地址:https://www.cnblogs.com/yfceshi/p/6786035.html
Copyright © 2020-2023  润新知