Encapsulate reusable custom adapters and pay tribute to Xiang Ge, Adapter
After reading Xiang GE's custom omnipotent adapter, I made my own notes and analyzed the thinking style of the experts, so that we can enter the inner world of abnormal programmers together.
Before analyzing the omnipotent adapter, let's first analyze the common adapter
public class ReportSpinnerAdapter extends BaseAdapter { private Context context; private List<String> str; public ReportSpinnerAdapter(Context context, List<String> str, int textWidth) { this.context = context; this.str = str; this.textWidth = textWidth; } @Override public int getCount() { return str.size(); } @Override public Object getItem(int position) { return str.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { Viewholder hold; if (convertView==null){ convertView = LayoutInflater.from(context).inflate(R.layout.spinner_layout,parent,false); hold = new ViewHold(); hold.textView = (TextView) convertView.findViewById(R.id.textView); convertView.setTag(hold); }else{ hold = (ViewHold) convertView.getTag(); } hold.textView.setText(str.get(position)); return convertView; } static class ViewHolder{ TextView textView; }
A normal adapter is roughly divided into two points: getView and ViewHolder. A class solves the problem and involves the reuse of controls. ViewHolder is used. The main logic is still in getView ,, if you do not understand this, you can first Baidu ViewHolder. The logic in getView is that if convertView is used for the first time, the binding layout is initialized and the tag is set. Otherwise, viewHolder is retrieved from convertView, if you want to change the parameters of the control in the layout, retrieve the control setting parameters from viewHolder. Because the control is initialized together during convertView initialization, you can set the parameters directly. This is a standard programmer's usual practice. However, if we need to use adapter frequently in our program and each Listview or GridView needs to get an adapter, it will waste a lot of time, as a perverted programmer, how can Xiang Ge endure it? So I have made such a blog, Xiang Ge blog, so that we can make profits from it. I have gained new technologies and new ways of thinking.
To sum up the custom omnipotent adapter, or reusable adapter, we can split it into three points:
1. encapsulate a special ViewHolder. You can pass in the parameter to get the viewHolder directly. In this step, kill the following:
if (convertView==null){ convertView = LayoutInflater.from(context).inflate(R.layout.spinner_layout,parent,false); hold = new ViewHold(); hold.textView = (TextView) convertView.findViewById(R.id.textView); convertView.setTag(hold); }else{ hold = (ViewHold) convertView.getTag(); }
To get rid of this step, you must think of the parameters passed in to get viewHolder directly. layoutInflater. from (context) 2. r. layout. spinner_layout 3. parent 4. convertView
You can simply write
Public class ViewHolder {private SparseArray <View> views; private View convertView; public ViewHolder (ViewGroup parent, LayoutInflater inflater, int layoutId) {this. views = new SparseArray <View> (); this. convertView = inflater. inflate (layoutId, parent, false); this. convertView. setTag (this );} /*** get viewHolder * @ param parent * @ param convertView * @ param inflater * @ param layoutId * @ return */public static ViewHolder getViewHolder (ViewGroup parent, View convertView, layoutInflater inflater, int layoutId) {if (convertView = null) {return new ViewHolder (parent, inflater, layoutId);} return (ViewHolder) convertView. getTag ();}
This SparseArray <View> views is actually a key-value pair used to save the control of each row or column in listview or gridview, which is more efficient than hashmap. usage is
/*** Get view by Id * @ param viewId * @ param <T> * @ return */public <T extends View> T getView (int viewId) {View view = views. get (viewId); if (view = null) {view = convertView. findViewById (viewId); views. put (viewId, view);} return (T) view ;}
In this way, a ViewHolder is ready.
2. writing a universal adapter is basically impossible. What should I do? To make a semi-universal adapter, since it is generally the same as a semi-universal adapter, there are a few differences, it is best to inherit from abstract classes.
public abstract class CommonAdapter<T> extends BaseAdapter { private List<T> list; private LayoutInflater inflater; private int layoutId; public CommonAdapter(List<T> list, Context context,int layoutId) { this.list = list; this.inflater = LayoutInflater.from(context); this.layoutId = layoutId; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = ViewHolder.getViewHolder(parent,convertView,inflater,layoutId); convert(viewHolder,list.get(position)); return viewHolder.getConvertView(); } public abstract void convert(ViewHolder viewHolder,T t);}
First, when we bind the adapter, we don't know the data source. We need to use a generic class and a generic set, and then pass in the layout id and context, set the place where values need to be assigned to the control as an abstract method and inherit from the subclass. After the encapsulation is completed, there are few things we need to do, you only need to override the convert method and constructor method.
Public class MyAdapter extends CommonAdapter <Bean> {public MyAdapter (List <Bean> list, Context context, int layoutId) {super (list, context, layoutId );} @ Override public void convert (ViewHolder viewHolder, Bean bean) {(TextView) viewHolder. getView (R. id. text )). setText ("this is test data 1"); (TextView) viewHolder. getView (R. id. text )). setText ("this is test data 1 ");}}
In this way, you only need to bind the MyAdapter in activity or fragment, and pass in the data and layout id and content. Only (viewHolder. getView (R. id. text )). setText is a tough way to write code. If you write strong code, you have to cut the cursor back. I am not used to it anyway. What should I do, now that we have a viewholder object, we will transform the viewHolder object to make the public code a little more, and we will write a little less in the future. Add the following method to ViewHolder:
/*** Get TextView by id * @ return */public TextView getTextView (int viewId) {return getView (viewId );} /*** obtain ImageView by id * @ return */public ImageView getImageView (int viewId) {return getView (viewId );} /*** get the Button * @ return */public Button getButton (int viewId) {return getView (viewId);} Based on the id );} /*** obtain RadioButton by id * @ return */public RadioButton getRadioButton (int viewId) {return getView (viewId );} /*** get CheckBox * @ return */public CheckBox getCheckBox (int viewId) {return getView (viewId );} /*** get ImageButton * @ return */public ImageButton getImageButton (int viewId) {return getView (viewId) according to the id );} /*** get ImageButton * @ return */public EditText getEditText (int viewId) {return getView (viewId) according to the id );}
The convert method in Myadapter can be written in this way.
@ Override public void convert (ViewHolder viewHolder, Bean bean) {viewHolder. getTextView (R. id. text ). setText ("this is test data 1"); viewHolder. getTextView (R. id. text ). setText ("this is test data 2 ");}
In this way, the writing will be smoother, better than hand. This is basically the main content of Xiang GE's omnipotent custom adapter. The core idea is illustrated below.
Finally, source code: Click to open the link