Build a reusable custom BaseAdapter
Introduction to this section:
As the title says, this section brings you the construction of a reusable custom BaseAdapter. We often involve ListView GridView and other Adapter controls require you to write another BaseAdapter class yourself, which is very troublesome. For another example, if we want to display two ListViews on one interface, we also need two BaseAdapters... Programmers like to be lazy. In this section, we will write a reusable custom BaseAdapter class~
1. Let’s start changing it bit by bit:
First 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());
return convertView;
}
//Add an element
public void add(Data data) {
if (mData == null) {
mData = new LinkedList<>();
}
mData.add(data);
notifyDataSetChanged();
}
//Add an element to a specific position
public void add(int position,Data data){
if (mData == null) {
mData = new LinkedList<>( ; = null) {
mData.remove(data); = null) {
mData.remove(position); ) {
mData.clear();
txt_content;
}
}
Upgrade 1: Set Entity to generic
Okay, after all, the Entitiy entity classes we pass may be all kinds of weird, such as Person, Book, Wether, etc., so we Set Entity to generic, 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<>( ; = null) {
mData.remove(data); = null) {
mData.remove(position); ) {
mData.clear();
txt_content;
}
}
Okay, what we did above is just to change the Data type to a generic T!
Upgrade 2: Upgrade of ViewHolder class:
Let’s first take a look at what our ViewHolder did before? Answer: findViewById, set the control status; 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:
- Define a method for finding controls. Our idea is to expose public methods and pass them when calling the method. Control id, and set content, such as TextView setting text: public ViewHolder setText(int id, CharSequence text){text setting}
- Move the convertView reuse part here, then you need to pass a context object, we need to get All parts are written into the constructor!
- Write a bunch of setting methods (public), such as setting text size, color, picture background, etc.!
Okay, let’s transform our ViewHolder class step by step
1) Relevant parameters and construction methods:
private SparseArray<View> mViews; //Storage View in ListView item
private View item; //Storage convertView
private int position; // Cursor
private Context context; //Context context
//Construction method to 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
Based on the above, we add another binding method
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 holder = (ViewHolder) convertView.getTag();
holder.item = convertView;
}
holder.position = position;
return holder;
}
3) Get the control saved in the collection according to the id
T t = (T) mViews.get(id);
if(t == null) {
t = (T) item.findViewById(id);
mViews .put(id, t);
}
return t;
}
4) 接着我们再定义一堆暴露出来的方法
*Get the current entry
*/
public View getItemView() {
return item;
}
/**
* Get entry location
*/
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 picture
*/
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 up click monitoring
*/
public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
getView(id).setOnClickListener(listener);
return this;
}
/**
* Settings are 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;
}
//其他方法可自行扩展
Okay, the transformation and upgrade of ViewHolder is completed~
Upgrade 3: Define an abstract method to complete the binding of ViewHolder and Data dataset
public abstract void bindView(ViewHolder holder, T obj);
We create a new BaseAdapter , just implement this method. In addition, don’t forget to customize our The BaseAdapter is changed 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, we write code to experience it:
We want to implement The rendering:
#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:
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);
//数据初始化
mData1 = new ArrayList<App>();
mData1.add(new App(R.mipmap.iv_icon_baidu,"百度"));
mData1.add(new App(R.mipmap.iv_icon_douban,"豆瓣"));
mData1.add(new App(R.mipmap.iv_icon_zhifubao,"支付宝"));
mData2 = new ArrayList<Book>();
mData2.add(new Book("《第一行代码Android》","郭霖"));
mData2.add(new Book("《Android群英传》","徐宜生"));
mData2.add(new Book("《Android开发艺术探索》","任玉刚"));
//Adapter初始化
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 reusable BaseAdapter we wrote is used as described above~
3. Code sample download:
ListViewDemo4.zip
Post Download the finally written MyAdapter class, which can be expanded according to your own 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; //存储ListView 的 item中的View
private View item; //存放convertView
private int position; //游标
private Context context; //Context上下文
//构造方法,完成相关初始化
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 entry
*/
public View getItemView() {
return item;
}
/**
*/
public int getItemPosition() {
return position;
}
/**
*/
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;
}
/**
*/
public ViewHolder setOnClickListener(int id, View.OnClickListener listener) {
getView(id).setOnClickListener(listener);
return this;
}
/**
* Settings are visible
*/
public ViewHolder setVisibility(int id, int visible) {
getView(id).setVisibility(visible);
return this;
}
/**
*/
public ViewHolder setTag(int id, Object obj) {
getView(id).setTag(obj);
return this;
}
//其他方法可自行扩展
}
}
Summary of this section:
This section introduces how to implement a reusable BaseAdapter. Of course, you can use this based on Modify according to your own needs, such as setting network images asynchronously, etc. The modified code is written with reference to Hong Yang’s video: Video link: Android - Creating a universal adapter. In addition, I encountered some problems during the actual writing. Thank you very much Berial(B神) for your patience~ありがとうございます~