Android Adapter的封装类CommonAdaper

#Android Adapter的封装类CommonAdaper

Android程序基本都是要用到ListView来显示数据,而ListView的显示必须要使用Adapter。
之前也写过几次BaseAdapter的封装类,但是这次这个封装类比之前任何一个都好用一些。

##一.先看效果:
1

##二.再看代码用法:

###1.MainActivity的代码:

package com.liwenzhi.asr.commonadapterdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {

    ListView listView;
    DeveloperAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initData();
        initEvent();
    }

    private void initView() {
        listView = findViewById(R.id.listView);
    }

    private void initData() {
        String[] items = {"开发者选项", "内存", "提交错误报告", "桌面备份密码", "不锁定屏幕"};
        adapter = new DeveloperAdapter(items);
        listView.setAdapter(adapter);

    }

    private void initEvent() {
        listView.setOnItemClickListener(this);
    }

    //ListView的条目点击事件
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

    }
}

###2.DeveloperAdaperd的代码

package com.liwenzhi.asr.commonadapterdemo;

import android.view.View;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;


import java.util.List;


public class DeveloperAdapter extends CommonAdapter<String> {//可以传入List的Bean类

    //构造方法自己定义,可以传入集合,数组,上下文。。。
    public DeveloperAdapter(List<String> list) {
        super(list);
    }

    public DeveloperAdapter(String[] list) {
        super(list);
    }

    //必须要重写的方法1,传入Item的布局
    @Override
    public int setLayoutRes() {
        return R.layout.item_developer;
    }

    //必须要重写的方法2,设置Item里面的数据显示
    @Override
    public void setData(CommonAdapter.ViewHolder holder, String data) {//这里的data是position对应的集合的数据,相当于getItem的数据
       //设置数据
        TextView tv_item_title = holder.getView(R.id.tv_item_title);
        tv_item_title.setText(data);
        //获取position动态改变图标
        int position = holder.getPosition();
        Switch switch_item = holder.getView(R.id.switch_item);
        ImageView iv_item = holder.getView(R.id.iv_item);
        //选择性显示图标
        if (position == 0 || position == 4) {
            switch_item.setVisibility(View.VISIBLE);
            iv_item.setVisibility(View.GONE);
        }
    }

}

###3.最后看一下这个CommonAdapter的封装类代码:

package com.liwenzhi.asr.commonadapterdemo;


import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import java.util.Arrays;
import java.util.List;

/**
 * 此类为listview adpter封装基类,用户继承此类后,必须实现此类中两个抽象方法,
 * 其他方法可根据需求决定是否重写
 */

public abstract class CommonAdapter<T> extends BaseAdapter {
    protected List<T> mData;

    //传入数组
    public CommonAdapter(T[] data) {
        mData = Arrays.asList(data);
    }

    //传入集合
    public CommonAdapter(List<T> data) {
        mData = data;
    }

    @Override
    public int getCount() {
        return mData == null ? 0 : mData.size();
    }

    @Override
    public Object 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) {
        ViewHolder holder = ViewHolder.getHolder(convertView, parent, position, setLayoutRes());
        setData(holder, mData.get(position));
        return holder.getConvertView();
    }

    public static class ViewHolder {
        //被点击的当前位置
        private int position;

        //用一个map集合来保存每个控件的id,这个SparseArray是android提供的一个比map使用效率更高的一个
        //集合,但是局限是,key只能是int类型,所以当键值对涉及到key是int类型时,可以优先考虑使用这个集合
        private SparseArray<View> array;

        //复用的布局
        private View convertView;

        public ViewHolder() {
        }

        //带三个构造的方法,这里将构造方法私有,防止外界去创建,通过自身的静态方法去创建对象即可
        private ViewHolder(ViewGroup parent, int position, int layout) {
            this.position = position;
            //每次创建对象,就将布局解析出来
            convertView = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
            //然后将对象保存到convertView对应的setTag中,方便每次该获取
            convertView.setTag(this);
            array = new SparseArray<>();
        }

        public static ViewHolder getHolder(View convertView, ViewGroup parent, int position, int layout) {
            //每次判断converView是否为空,如果为空就直接返回这个创建的对象
            if (convertView == null) {
                return new ViewHolder(parent, position, layout);
            } else {
                //不为空的情况,就跟我们上面的代码一样,每次通过复用的控件拿到对应的ViewHolder对象
                ViewHolder holder = (ViewHolder) convertView.getTag();
                //这里一定要更新下下标的位置,虽然对象相同,但是我们每次都要更新现有的位置,
                holder.position = position;
                //返回已经创建好的holder对象
                return holder;
            }
        }

        /**
         * 这个方法是通过控件id拿到对应的控件
         */
        public <T extends View> T getView(int viewId) {
            //每次通过viewId键去拿到到对应的控件
            View view = array.get(viewId);
            //如果为空,表示该集合中还没有存入该控件
            if (view == null) {
                //先要去通过converView拿到控件id
                view = convertView.findViewById(viewId);
                //保存到集合中,以便下次直接获取
                array.put(viewId, view);
            }
            //返回View的子类控件,采用泛型的方便是不需要强制转换了
            return (T) view;
        }

        //得到convertView布局
        public View getConvertView() {
            return convertView;
        }

        public int getPosition() {
            return position;
        }

    }

    /**
     * 实现此方法,返回具体的item布局资源ID
     */
    public abstract int setLayoutRes();

    /**
     * 实现此方法,需要获取item子控件,并且为每一个控件设置数据
     *
     * @param holder 基类返回的holder,通过holder的getView方法可以获取item中的子控件
     * @param t      数据对象的泛型,继承此类后,泛型类型确定
     */
    public abstract void setData(ViewHolder holder, T t);

}

上面的CommonAdapter已经高度封装了BaseAdapter,不需要自己写ViewHolder。
如果有特殊需求可以自己进行简单修改。

#共勉:认准并发挥自己的特长,就有机会成功。