Android builds a reusable custom BaseAdapter

Introduction to this section:

As the title, what this section brings to you is to build a reusable custom BaseAdapter. Whenever we involve other Adapter controls such as ListView GridView, we need to write another BaseAdapter class ourselves, which is very troublesome. For example, we If we want to display two ListViews on one interface, we also need two BaseAdapters... Well, programmers like to be lazy. In this section, we will write a reusable custom BaseAdapter class~


1. Let's start to change a little bit:

First of all, we paste the custom BaseAdapter written in the previous section, and we will upgrade it later

/**
 * Created by Jay on 2015/9/21 0021.
 */
public class MyAdapter extends BaseAdapter {

    private Context mContext;
    private LinkedList<Data> mData;

    public MyAdapter() {
    }

    public MyAdapter(LinkedList<Data> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }

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

    @Override
    public Object getItem(int position) {
        return null;
    }

    @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 = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent()); 
        if(mData != null) {
        return convertView; 
    } 

    //add an element 
    public void add(Data data) { 
        if (mData == null) { 
            mData = new LinkedList<>(); 
        } 
        mData.add(data); 
        notifyDataSetChanged(); 
    } 

    //go Specific position, add an element 
    public void add(int position,Data data){ 
        if (mData == null) { 
            mData = new LinkedList<>(); 
        } 
        mData.add(position, data); 
        notifyDataSetChanged(); 
    } 

    public void remove(Data data) { 
            mData. remove(data); 
        } 
        notifyDataSetChanged(); 
    }

    public void remove(int position) {
        if(mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }

    public void clear() {
        if(mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }

    private class ViewHolder {
        ImageView img_icon;
        TextView txt_content;
    }

}

Upgrade 1: Set Entity as generic

Ok, after all, the Entity entity class we passed may be strange, such as Person, Book, Wether, etc., so we set Entity as generic, and the modified code is as follows:

public class MyAdapter<T> extends BaseAdapter {

    private Context mContext;
    private LinkedList<T> mData;

    public MyAdapter() {
    }

    public MyAdapter(LinkedList<T> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }

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

    @Override
    public Object getItem(int position) {
        return null;
    }

    @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 = LayoutInflater.from(mContext).inflate(R.layout.item_list, parent, false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent()); 
        return convertView;
    } 

    //Add an element 
    public void add(T data) { 
        if (mData == null) { 
            mData = new LinkedList<>(); 
        } 
        mData.add(data); 
        notifyDataSetChanged(); 
    } 

    //Add an element to a specific position 
    public void add(int position,T data){ 
        if (mData == null) { 
            mData = new LinkedList<>(); 
        } 
        mData.add(position, data); 
        notifyDataSetChanged(); 
    } 

    public void remove(T data) { 
        if(mData != null) { 
            mData.remove(data); 
        } 
        notifyDataSetChanged(); 
    } 

    public void remove(int position) {
        if(mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }

    public void clear() {
        if(mData != null) {
            mData.clear();
        }
        notifyDataSetChanged();
    }

    private class ViewHolder {
        ImageView img_icon;
        TextView txt_content;
    }

}

Ok, what we did above is just to replace the Data type with the generic type T!


Upgrade 2: Upgrade of the ViewHolder class:

Let's take a look at what our ViewHolder did earlier? Answer: findViewById, set the state of the control; Next, we want to write most of the logic of the getView() method into the ViewHolder class on the basis of completing this. What this ViewHolder has to do:

  • To define a method for finding controls, our idea is to expose the public method, pass the control id and the set content when calling the method, such as TextView setting text: public ViewHolder setText(int id, CharSequence text){text setting}
  • Move the reuse part of convertView here, then you need to pass a context object, and we write all the parts that need to be obtained into the construction method!
  • Write a bunch of setting methods (public), such as setting text size and color, picture background, etc.!

Ok, let's transform our ViewHolder class step by step


1) Related parameters and construction methods:

public static class ViewHolder { private SparseArray<View> mViews; //store View 
    private View item 

    in ListView item ; //store convertView 
    private int position; //cursor 
    private Context context; //Context context 
    //construction method, complete Related initialization 
    private ViewHolder(Context context, ViewGroup parent, int layoutRes) { 
        mViews = new SparseArray<>(); 
        this.context = context; 
        View convertView = LayoutInflater.from(context).inflate(layoutRes, parent,false); 
        convertView .setTag(this); 
        item = convertView; 
    } 
    ImageView img_icon; 
    TextView txt_content; 
}



2) Bind ViewHolder and Item

On the basis of the above, we add another binding method

//绑定ViewHolder与item
public static ViewHolder bind(Context context, View convertView, ViewGroup parent,
                              int layoutRes, int position) {
    ViewHolder holder;
    if(convertView == null) {
        holder = new ViewHolder(context, parent, layoutRes);
    } else {
        holder = (ViewHolder) convertView.getTag();
        holder.item = convertView;
    }
    holder.position = position;
    return holder;
}

3) Get the controls saved in the collection according to the id

public <T extends View> T getView(int id) {
    T t = (T) mViews.get(id);
    if(t == null) {
        t = (T) item.findViewById(id);
        mViews.put(id, t);
    }
    return t;
}

4) Then we define a bunch of exposed methods

/** 
 * Get current item 
 */ 
public View getItemView() { 
    return item; 
} 

/** 
 * Get item position 
 */ 
public int getItemPosition() { 
    return position; 
} 

/** 
 * Set text 
 */ 
public ViewHolder setText( int id, CharSequence text) { 
    View view = getView(id); 
    if(view instanceof TextView) { 
        ((TextView) view).setText(text); 
    } 
    return this; 
} 

/** 
 * set image 
 */ 
public ViewHolder setImageResource (int id, int drawableRes) { 
    View view = getView(id); 
    if(view instanceof ImageView) {
        ((ImageView) view).setImageResource(drawableRes); 
    } else { 
        view.setBackgroundResource(drawableRes); 
    } 
    return this; 
} 


/** 
 * Set click listener 
 */ 
public ViewHolder setOnClickListener(int id, View.OnClickListener listener) { 
    getView (id).setOnClickListener(listener); 
    return this; 
} 

/** 
 * Set visible 
 */ 
public ViewHolder setVisibility(int id, int visible) { 
    getView(id).setVisibility(visible); 
    return this; 
} 

/** 
 * set tag 
 */ 
public ViewHolder setTag(int id, Object obj) { 
    getView(id).setTag(obj);
    return this;  
}

//Other methods can be extended by themselves

Ok, the upgrade of ViewHolder is complete~


Upgrade 3: Define an abstract method to complete the binding of ViewHolder and Data dataset

public abstract void bindView(ViewHolder holder, T obj);

When we create a new BaseAdapter, just implement this method. In addition, don't forget to change our custom BaseAdapter to abstract!


Upgrade 4: Modify the content of the getView() part

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
            , position);
    bindView(holder,getItem(position));
    return holder.getItemView();
}

2. After the upgrade is complete, let's write code to experience:

The rendering we want to achieve:

There are two lists above with different layouts, but I only use one BaseAdapter class to achieve the above effect!

The key code is as follows:

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Context mContext;
    private ListView list_book;
    private ListView list_app;

    private MyAdapter<App> myAdapter1 = null;
    private MyAdapter<Book> myAdapter2 = null;
    private List<App> mData1 = null;
    private List<Book> mData2 = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        init();

    }

    private void init() {

        list_book = (ListView) findViewById(R.id.list_book);
        list_app = (ListView) findViewById(R.id.list_app); 

        //Data initialization 
        mData1 = new ArrayList<App>(); 
        mData1.add(new App(R.mipmap.iv_icon_baidu,"Baidu")); 
        mData1.add (new App(R.mipmap.iv_icon_douban,"Douban")); 
        mData1.add(new App(R.mipmap.iv_icon_zhifubao,"Alipay")); 

        mData2 = new ArrayList<Book>(); 
        mData2.add(new Book(""The first line of code Android"","Guo Lin")); 
        mData2.add(new Book(""Android Heroes"","Xu Yisheng")); 
        mData2.add(new Book("《 Android Development Art Exploration","Ren Yugang")); 

        //Adapter initialization 
        myAdapter1 = new MyAdapter<App>((ArrayList)mData1,R.layout.item_one) {
            @Override
            public void bindView(ViewHolder holder, App obj) { 
                holder.setImageResource(R.id.img_icon,obj.getaIcon());
                holder.setText(R.id.txt_aname,obj.getaName());
            }
        };
        myAdapter2 = new MyAdapter<Book>((ArrayList)mData2,R.layout.item_two) {
            @Override
            public void bindView(ViewHolder holder, Book obj) {
                holder.setText(R.id.txt_bname,obj.getbName());
                holder.setText(R.id.txt_bauthor,obj.getbAuthor());
            }
        };

        //ListView设置下Adapter:
        list_book.setAdapter(myAdapter2);
        list_app.setAdapter(myAdapter1);

    }


}

The use of the reusable BaseAdapter we wrote is as described above~


3. Code sample download:

ListViewDemo4.zip

Paste the last written MyAdapter class, which can be expanded according to your needs:

MyAdapter.java

/**
 * Created by Jay on 2015/9/22 0022.
 */
public abstract class MyAdapter<T> extends BaseAdapter {

    private ArrayList<T> mData;
    private int mLayoutRes;           //布局id


    public MyAdapter() {
    }

    public MyAdapter(ArrayList<T> mData, int mLayoutRes) {
        this.mData = mData;
        this.mLayoutRes = mLayoutRes;
    }

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

    @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) {
        ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes
                , position);
        bindView(holder, getItem(position));
        return holder.getItemView();
    }

    public abstract void bindView(ViewHolder holder, T obj);

    //添加一个元素
    public void add(T data) {
        if (mData == null) {
            mData = new ArrayList<>();
        }
        mData.add(data);
        notifyDataSetChanged();
    }

    //往特定位置,添加一个元素
    public void add(int position, T data) {
        if (mData == null) {
            mData = new ArrayList<>();
        }
        mData.add(position, data);
        notifyDataSetChanged();
    }

    public void remove(T data) {
        if (mData != null) {
            mData.remove(data);
        }
        notifyDataSetChanged();
    }

    public void remove(int position) {
        if (mData != null) {
            mData.remove(position);
        }
        notifyDataSetChanged();
    }

    public void clear() {
        if (mData != null) { 
            mData.clear(); 
        } 
        notifyDataSetChanged(); 
    } 


    public static class ViewHolder { 

        private SparseArray<View> mViews; // store View private View item in ListView item 
        ; // store convertView 
        private int position; //Cursor 
        private Context context; //Context context 

        //Construction method, complete related initialization 
        private ViewHolder(Context context, ViewGroup parent, int layoutRes) { 
            mViews = new SparseArray<>(); 
            this.context = context; 
            View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false);
            convertView.setTag(this);
            item = convertView;
        }

        //绑定ViewHolder与item
        public static ViewHolder bind(Context context, View convertView, ViewGroup parent,
                                      int layoutRes, int position) {
            ViewHolder holder;
            if (convertView == null) {
                holder = new ViewHolder(context, parent, layoutRes);
            } else {
                holder = (ViewHolder) convertView.getTag();
                holder.item = convertView;
            }
            holder.position = position;
            return holder;
        }

        @SuppressWarnings("unchecked") 
        public <T extends View> T getView(int id) { 
            T t = (T) mViews.get(id); 
            if (t == null) { 
                t = (T) item.findViewById( id); 
                mViews.put(id, t); 
            } 
            return t; 
        } 


        /** 
         * Get the current item 
         */ 
        public View getItemView() { 
            return item; 
        } 

        /** 
         * Get the item position 
         */ 
        public int getItemPosition() { 
            return position; 
        } 

        /** 
         * Set text
         */
        public ViewHolder setText(int id, CharSequence text) {
            View view = getView(id);
            if (view instanceof TextView) {
                ((TextView) view).setText(text);
            }
            return this;
        }

        /**
         * 设置图片
         */
        public ViewHolder setImageResource(int id, int drawableRes) {
            View view = getView(id);
            if (view instanceof ImageView) {
                ((ImageView) view).setImageResource(drawableRes);
            } else {
                view.setBackgroundResource(drawableRes);
            }
            return this; 
        } 


        /** 
         * Set click listener 
         */ 
        public ViewHolder setOnClickListener(int id, View.OnClickListener listener) { 
            getView(id).setOnClickListener(listener); 
            return this; 
        } 

        /** 
         * Set visible 
         */ 
        public ViewHolder setVisibility(int id, int visible) { 
            getView(id).setVisibility(visible); 
            return this; 
        } 

        /** 
         * set tag 
         */ 
        public ViewHolder setTag(int id, Object obj) { 
            getView(id).setTag(obj );
            return this; 
        } 

        //Other methods can be extended by yourself 

    } 

}

Guess you like

Origin blog.csdn.net/leyang0910/article/details/131073969