zoukankan      html  css  js  c++  java
  • Android_ListView适配器

    ListView如何优化

    • 复用convertView缓存(减少ListView绘制).
    • 自定义静态类ViewHolder(减少findViewById次数),通过setTag()、getTag()获取holder实例.
    • 使用分页加载.
    • 使用软引用WeakReference引用ImageView对象:当item划出屏幕,可以释放对大图片的引用,节省内存,提高效率.
    • 另外对图片还可以使用LruCache和三级缓存来优化.

    正常使用方式

    public class MyAdapter extends BaseAdapter {
    
        private LayoutInflater mInflater;
        private Context ctx;
        private List<String> mDatas;
    
        public MyAdapter(Context ctx, List<String> mDatas) {
            mInflater = LayoutInflater.from(ctx);
            this.ctx = ctx;
            this.mDatas = mDatas;
        }
    
        @Override
        public int getCount() {
            return mDatas.size(); // 固定
        }
    
        @Override
        public Object getItem(int position) {
            return mDatas.get(position); // 固定
        }
    
        @Override
        public long getItemId(int position) {
            return position; // 固定
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null) { // 复用convertView缓存
                convertView = mInflater.inflate(R.layout.item_str, null); // 条目布局
                holder = new ViewHolder();
                holder.tv = (TextView) convertView.findViewById(R.id.tv); // holder存储控件
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.tv.setText(mDatas.get(position));
            return convertView;
        }
    
        private final class ViewHolder {
            TextView tv;
        }
    }

    上述代码大家都很熟悉,基本遇到就是一套,都写烂了,分析一下

    • 复写的三个方法都是固定的,很好抽取.
    • getView中通过set、get处理ViewHolder对象可以抽取.
    • holder中的findViewById可以抽取.

    提炼

    PART_A:Adapter

    package com.catface.cadapter;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import java.util.List;
    
    /** * @desc 使用泛型,接收不同类型的对象 */
    public abstract class CAdapter<T> extends BaseAdapter {
        protected Context ctx; 
        protected List<T> datas; 
        protected LayoutInflater inflater;
        private int layoutId; 
    
        // arg1-3:上下文 | 集合<泛型bean> | 条目布局
        public CAdapter(Context ctx, List<T> datas, int layoutId) { 
            this.ctx = ctx;
            this.datas = datas;
            this.inflater = LayoutInflater.from(ctx);
            this.layoutId = layoutId;
        }
    
        @Override public int getCount() {
            return datas == null ? 0 : datas.size();
        }
    
        @Override public T getItem(int position) {
            return datas == null ? null : datas.get(position);
        }
    
        @Override public long getItemId(int position) {
            return position;
        }
    
        /** * @desc 1.获取ViewHolder对象(上下文、复用缓存、父布局、条目布局) */
        @Override public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = ViewHolder.get(ctx, convertView, parent, layoutId, position);
            convert(holder, getItem(position)); // ------>> 暴露抽象方法
            return holder.getConvertView(); // 设置结束各个组件,返回ViewHolder对象方便继续设置控件值
        }
    
        /** * @desc 暴露出去并传入holder与bean:拿着控件设置值 */
        public abstract void convert(ViewHolder holder, T t);
    }

    PART_B:ViewHolder

    package com.catface.cadapter;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Paint;
    import android.graphics.Typeface;
    import android.graphics.drawable.Drawable;
    import android.os.Build;
    import android.text.util.Linkify;
    import android.util.SparseArray;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.AlphaAnimation;
    import android.widget.Checkable;
    import android.widget.ImageView;
    import android.widget.ProgressBar;
    import android.widget.RatingBar;
    import android.widget.TextView;
    
    /** * @desc 待修复问题: * * 1.CheckBox选中错位(复用convertView所致) √ * a.在Bean中添加isChecked字段 * b.在ListView中用ArrayList数组记录holder中当前选中的CheckBox * * 2.图片显示错位 × * * 3.上拉刷新 + 下拉加载 × */
    public class ViewHolder {
        private Context ctx; // 上下文
        private View convertView; // 复用缓存
        private int mLayoutId; // 条目布局
        private SparseArray<View> views; // 各组件及对应id(SparseArray代替HashMap,提高效率)
        private int position;
    
        public ViewHolder(Context ctx, ViewGroup parent, int layoutId, int position) {
            this.ctx = ctx;
            this.convertView = LayoutInflater.from(ctx).inflate(layoutId, parent, false);
            this.mLayoutId = layoutId;
            this.views = new SparseArray<View>();
            this.position = position;
            this.convertView.setTag(this);
        }
    
        /** * @desc 通过setTag()和getTag()来获取ViewHolder对象 */
        public static ViewHolder get(Context ctx, View convertView, ViewGroup parent, int layoutId, int position) {
            if (convertView == null) {
                return new ViewHolder(ctx, parent, layoutId, position);
            } else {
                ViewHolder holder = (ViewHolder) convertView.getTag();
                holder.position = position;
                return holder;
            }
        }
    
        /** * @desc 获取当前holder的position */
        public int getPosition() {
            return position;
        }
    
        public int getLayoutId() {
            return mLayoutId;
        }
    
        /** * @desc 通过viewId获取控件 */
        @SuppressWarnings("unchecked")
        public <T extends View> T getViewByViewId(int viewId) {
            View view = views.get(viewId);
            if (view == null) {
                view = convertView.findViewById(viewId);
                views.put(viewId, view);
            }
            return (T) view;
        }
    
        public View getConvertView() {
            return convertView;
        }
    
        /************************************************ PS:图片可以使用第三方工具类加载图片 ************************************************/
    
        /** 设置TextView文本 */
        public ViewHolder setText(int viewId, String text) {
            ((TextView) getViewByViewId(viewId)).setText(text);
            return this;
        }
    
        /** 设置TextView颜色 */
        public ViewHolder setTextColor(int viewId, int textColor) {
            ((TextView) getViewByViewId(viewId)).setTextColor(textColor);
            return this;
        }
    
        /** 设置TextView颜色 */
        public ViewHolder setTextColorRes(int viewId, int textColorRes) {
            ((TextView) getViewByViewId(viewId)).setTextColor(ctx.getResources().getColor(textColorRes));
            return this;
        }
    
        /** 设置文本字体 */
        public ViewHolder setTypeface(Typeface typeface, int... viewIds) {
            for (int viewId : viewIds) {
                TextView view = getViewByViewId(viewId);
                view.setTypeface(typeface);
                view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
            }
            return this;
        }
    
        /** 设置图片:资源id */
        public ViewHolder setImageResource(int viewId, int resId) {
            ((ImageView) getViewByViewId(viewId)).setImageResource(resId);
            return this;
        }
    
        /** 设置图片:Bitmap */
        public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
            ((ImageView) getViewByViewId(viewId)).setImageBitmap(bitmap);
            return this;
        }
    
        /** 设置图片:Drawable */
        public ViewHolder setImageDrawable(int viewId, Drawable drawable) {
            ((ImageView) getViewByViewId(viewId)).setImageDrawable(drawable);
            return this;
        }
    
        /** 设置背景色 */
        public ViewHolder setBackgroundColor(int viewId, int color) {
            getViewByViewId(viewId).setBackgroundColor(color);
            return this;
        }
    
        /** 设置背景色 */
        public ViewHolder setBackgroundRes(int viewId, int backgroundRes) {
            getViewByViewId(viewId).setBackgroundResource(backgroundRes);
            return this;
        }
    
        @SuppressLint("NewApi")
        public ViewHolder setAlpha(int viewId, float value) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                getViewByViewId(viewId).setAlpha(value);
            } else {
                // Pre-honeycomb hack to set Alpha value
                AlphaAnimation alpha = new AlphaAnimation(value, value);
                alpha.setDuration(0);
                alpha.setFillAfter(true);
                getViewByViewId(viewId).startAnimation(alpha);
            }
            return this;
        }
    
        /** 设置可见状态 */
        public ViewHolder setVisible(int viewId, boolean visible) {
            getViewByViewId(viewId).setVisibility(visible ? View.VISIBLE : View.GONE);
            return this;
        }
    
        public ViewHolder linkify(int viewId) {
            TextView view = getViewByViewId(viewId);
            Linkify.addLinks(view, Linkify.ALL);
            return this;
        }
    
        /** 设置进度 */
        public ViewHolder setProgress(int viewId, int progress) {
            ((ProgressBar) getViewByViewId(viewId)).setProgress(progress);
            return this;
        }
    
        /** 设置最大进度 */
        public ViewHolder setMax(int viewId, int max) {
            ProgressBar view = getViewByViewId(viewId);
            view.setMax(max);
            return this;
        }
    
        /** 设置进度、最大进度 */
        public ViewHolder setProgress(int viewId, int progress, int max) {
            ProgressBar view = getViewByViewId(viewId);
            view.setMax(max);
            view.setProgress(progress);
            return this;
        }
    
        public ViewHolder setRating(int viewId, float rating) {
            RatingBar view = getViewByViewId(viewId);
            view.setRating(rating);
            return this;
        }
    
        public ViewHolder setRating(int viewId, float rating, int max) {
            RatingBar view = getViewByViewId(viewId);
            view.setMax(max);
            view.setRating(rating);
            return this;
        }
    
        public ViewHolder setTag(int viewId, Object tag) {
            View view = getViewByViewId(viewId);
            view.setTag(tag);
            return this;
        }
    
        public ViewHolder setTag(int viewId, int key, Object tag) {
            View view = getViewByViewId(viewId);
            view.setTag(key, tag);
            return this;
        }
    
        public ViewHolder setChecked(int viewId, boolean checked) {
            Checkable view = (Checkable) getViewByViewId(viewId);
            view.setChecked(checked);
            return this;
        }
    
        /** 设置点击事件 */
        public ViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
            getViewByViewId(viewId).setOnClickListener(listener);
            return this;
        }
    
        /** 设置触摸事件 */
        public ViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) {
            getViewByViewId(viewId).setOnTouchListener(listener);
            return this;
        }
    
        /** 设置长按事件 */
        public ViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) {
            getViewByViewId(viewId).setOnLongClickListener(listener);
            return this;
        }
    }

    PART_C:多条目的Adapter

    • 接口
    package com.catface.cadapter;
    
    /** * @desc 多条目ListView的Adapter接口 */
    public interface IMultiCAdapter<T> {
        int getLayoutId(int position, T t);
    
        int getViewTypeCount();
    
        int getItemViewType(int postion, T t);
    }
    • 具体Adapter
    package com.catface.cadapter;
    
    import android.content.Context;
    import android.view.View;
    import android.view.ViewGroup;
    import java.util.List;
    
    /** * @desc 多条目的Adapter */
    public abstract class MultiCAdapter<T> extends CAdapter<T> {
    
        protected IMultiCAdapter<T> mMultiItemTypeSupport;
    
        public MultiCAdapter(Context context, List<T> datas, IMultiCAdapter<T> multiItemTypeSupport) {
            super(context, datas, -1);
            this.mMultiItemTypeSupport = multiItemTypeSupport;
        }
    
        @Override public int getViewTypeCount() {
            if (mMultiItemTypeSupport != null) {
                return mMultiItemTypeSupport.getViewTypeCount();
            }
            return super.getViewTypeCount();
        }
    
        @Override public int getItemViewType(int position) {
            if (mMultiItemTypeSupport != null) {
                return mMultiItemTypeSupport.getItemViewType(position, datas.get(position));
            }
            return super.getItemViewType(position);
    
        }
    
        @Override public View getView(int position, View convertView, ViewGroup parent) {
            if (mMultiItemTypeSupport == null) {
                return super.getView(position, convertView, parent);
            }
            int layoutId = mMultiItemTypeSupport.getLayoutId(position, getItem(position));
            ViewHolder viewHolder = ViewHolder.get(ctx, convertView, parent, layoutId, position);
            convert(viewHolder, getItem(position));
            return viewHolder.getConvertView();
        }
    }

    提炼成果

    • 普通条目调用方式
    setListAdapter(new CAdapter<Person>(getActivity(), datas, R.layout.item_fragment1) {
        @Override
        public void convert(ViewHolder viewHolder, Person person) {
            viewHolder.setText(R.id.tv_name, person.getName()).setText(R.id.tv_age, person.getAge() + "").setImageResource(R.id.iv_icon, person.getIcon());
        }
    });
    • 带CheckBox等控件,解决其抢占item事件的方法 
      • 条目布局父控件:android:descendantFocusability="blocksDescendants"
      • CheckBox:android:focusable="false"
    setListAdapter(new CAdapter<Person>(getActivity(), datas, R.layout.item_fragment1up) {
    
        private List<Integer> points = new ArrayList<Integer>();
    
        @Override
        public void convert(final ViewHolder viewHolder, Person person) {
            viewHolder.setText(R.id.tv_name, person.getName()).setText(R.id.tv_age, person.getAge() + "").setImageResource(R.id.iv_icon, person.getIcon());
    
            final CheckBox cb = (CheckBox) viewHolder.getViewByViewId(R.id.cb_f1up);
            cb.setChecked(false); // 先置为false
            if (points.contains(viewHolder.getPosition())) {
                cb.setChecked(true);
            }
            cb.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                if (cb.isChecked()) {
                    points.add(viewHolder.getPosition());
                } else {
                    points.remove((Integer) viewHolder.getPosition());
                }
            }
        });
    }
  • 相关阅读:
    [Android Studio] Android Studio底边栏选项不见了,如何调出来
    [Android Studio] Android Studio中查看类的继承关系
    [Android Studio] Android Studio如何提示函数用法
    [Android Studio] Android Studio如何查看branch列表及切换branch(转载)
    [Android Studio] Android Studio使用教程(二)
    [Android Studio] Android Studio使用教程(一)
    [Android Studio] Android Studio移除的Module如何恢复(转载)
    [Android Studio] Android Studio如何删除module(转载)
    [Linux] ubuntu下查看CHM的软件
    python 在Windows中描述路径时出现的问题
  • 原文地址:https://www.cnblogs.com/YFeiY7/p/5917643.html
Copyright © 2011-2022 走看看