Project Address: Https://github.com/JoanZapata/base-adapter-helper
1. Function Introduction 1.1. Base-adapter-helper
Base-adapter-helper is an encapsulation of the traditional baseadapter viewholder pattern. The main function is to simplify the code we write Abslistview Adapter, such as Listview,gridview.
1.2 Basic use
mListView.setAdapter(mAdapter = new QuickAdapter<Bean>(MainActivity.this, R.layout.item_list, mDatas) { @Override protected void convert(BaseAdapterHelper helper, Bean item) { helper.setText(R.id.tv_title, item.getTitle()); helper.setImageUrl(R.id.id_icon, item.getUrl()); helper.setText(R.id.tv_describe, item.getDesc()); helper.setText(R.id.tv_phone, item.getPhone()); helper.setText(R.id.tv_time, item.getTime()); }});
1.3 Advantages
(1) Providing Qucikadapter, omitting the writing of abstract functions like GetCount (), just focus on the display of Model to View.
(2) Baseadapterhelper contains a number of auxiliary methods for View operations, such as loading images from the network:
helper.setImageUrl(R.id.iv_photo, item.getPhotoUrl());
1.4 Disadvantages
(1) with Picasso coupling, want to replace with other image cache need to change the source code.
Can be done by means of an interface. For the three-party based on their own image cache library to achieve picture acquisition, or directly remove the helper.setImageUrl(…) function.
(2) with an internal join progress bar occasionally, resulting in multiple types of layouts not supported
At the end of this paper, we give a solution to not modify the progress bar. A better implementation should be exposed by means of an interface, for the three parties to set themselves.
(3) The current plan does not support it HeaderViewListAdapter .
Overall, the cubby is simpler and the implementation needs to be improved.
2. Overall design
Because Base-adapter-helper is essentially still the viewholder pattern, the following are respectively Base-adapter-helper's overall design diagram and Viewholder pattern design, through the comparison of the two graphs. Can see that base-adapter-helper to the traditional implementation of the BaseAdapter preliminary ( QuickAdapter ), and its sub-class only need to implement the convert(…) method, in the convert(…) can get BaseAdapterHelper , the BaseAdapterHelper equivalent ViewHolder . However, it provides a lot of auxiliary methods in the interior. Used to set the data and events on the View.
Base-adapter-helpr
Viewholder Pattern
3. Specific design of the 3.1 class diagram
This is the main class diagram for the Base-adapter-helper library.
(1) The general abstract method in Baseadapter is implemented in Basequcikadapter.
(2) Basequickadapter in two generics, where T represents the Data entity class (Bean) type, and H represents Baseadapterhelper or its subclasses.
(3) Qucikadapter inherit from Basequickadapter, and pass in Baseadapterhelper as H generic type;
(4) Enhancedquickadapter The main convert(…) method of adding a itemchanged. Indicates whether the item corresponding data has changed;
(5) Baseadapterhelper is an auxiliary class for obtaining View and related operations such as content, event settings, and so on. Most of the methods used for setup are chained programming for easy writing.
(6) can be extended according to their own need to inherit Baseadapterhelper, as the Basequickadapter subclass of the H generic type.
3.2 Core class source code Analysis 3.2.1 Basequcikadapter.java
This class inherits from Baseadapter. Complete the implementation of some general abstract methods in Baseadapter, similar ArrayAdapter .
The class declares two generics, where T represents the Data entity class (Bean) type. H represents Baseadapterhelper or its subclasses, which are used primarily BaseAdapterHelper when expanding.
(1) Construction method
public BaseQuickAdapter(Context context, int layoutResId) { this(context, layoutResId, null);}public BaseQuickAdapter(Context context, int layoutResId, List<T> data) { this.data = data == null ?
new ArrayList<T>() : new ArrayList<T>(data); this.context = context; this.layoutResId = layoutResId;}
The Itemview layout file of the Adapter must be specified by Layoutresid, and the data to be displayed is specified via data.
(2) The main methods that have been implemented
@Overridepublic int getCount() { int extra = displayIndeterminateProgress ? 1 : 0; return data.size() + extra;}@Overridepublic int getViewTypeCount() { return 2;}@Overridepublic int getItemViewType(int position) { return position >= data.size() ? 1 : 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) { if (getItemViewType(position) == 0) { final H helper = getAdapterHelper(position, convertView, parent); T item = getItem(position); helper.setAssociatedObject(item); convert(helper, item); return helper.getView(); } return createIndeterminateProgressView(convertView, parent);}
The main methods that have been implemented in Basequcikadapter are listed above, similar to the general Baseadapter, and we focus on the following points:
A. Rewritten getViewTypeCount() and getItemViewType() , here type is 2, by getView(…) being able to see, primarily to show a progress bar at the end of the Abslistview. Here also exposes a disadvantage, unable to support a variety of Item style layout;
B. getView(…) the implementation of the method first getAdapterHelper(…) obtains baseadapterhelper and item through the abstract function, then convert(…) realizes the View and the data binding through the abstract function.
Such BaseQucikAdapter subclasses only need to implement abstract functions getAdapterHelper(…) and convert(…) can.
(3) Abstract method to be implemented
protected abstract void convert(H helper, T item);protected abstract H getAdapterHelper(int position, View convertView, ViewGroup parent);
A. Convert (H helper, T Item)
by helper binding View and data.
helperThe number of references represents Basequickadapter or its subclasses. Used to get a View and make content, event settings, and other related operations, returned by the getAdapterHelper(…) function, item representing the corresponding data.
B. getadapterhelper (int position, View Convertview, ViewGroup parent)
Returns the Basequickadapter or its subclasses, binds the item, and then returns the value passed to the convert(…) function above.
getAdapterHelper(…)the implementation of this is QuickAdapter described below.
3.2.2 Qucikadapter.java
This class inherits from BaseQuickAdapter , there is no code, is mainly used to provide a high-speed use of the Adapter.
For getAdapterHelper(…) the function returned directly BaseAdapterHelper . In general, this class can be used directly as a Adapter, such as 1.2 基本使用 a demo sample.
But suppose you extend BaseAdapterHelper it, the overriding getAdapterHelper(…) function returns it. Can realize their own Adapter.
3.2.3 Enhancedquickadapter.java
Inherited from QuickAdapter , but convert(…) added a number of parameters itemChanged . Indicates whether the item's corresponding data has changed.
@Overrideprotected final void convert(BaseAdapterHelper helper, T item) { boolean itemChanged = helper.associatedObject == null || !helper.associatedObject.equals(item); helper.associatedObject = item; convert(helper, item, itemChanged);}protected abstract void convert(BaseAdapterHelper helper, T item, boolean itemChanged);
Being able to see its implementation is helper.associatedObject a equals() way to infer whether the data has changed, Associatedobject is our bean.
In the BaseQuickAdapter.getView(…) code that can see its assignment.
3.2.4 Baseadapterhelper.java
An auxiliary class that can be used to get a View and perform related operations such as content settings, which have the following functions:
(1) acts as a viewholder role, the KV form holds the ID of the Convertview neutron View and its reference, convenient to find.
and Convertview through tag association;
(2) provides a bunch of auxiliary methods for setting content, styles, events, and so on for a child View.
(1) Construction-related methods
Protected Baseadapterhelper (Context context, viewgroup parent, int layoutid, int position) {this.context = Context; This.position = position; This.views = new sparsearray<view> (); Convertview = Layoutinflater.from (context)//. Inflate (LayoutID, parent, false); Convertview.settag (this);} public static Baseadapterhelper Get (context context, View Convertview, viewgroup parent, int layoutid) {return get (con Text, Convertview, parent, LayoutID,-1);} /** This method is the package private and should only being used by Quickadapter. */static Baseadapterhelper Get (context context, View Convertview, viewgroup parent, int layoutid, int position) {if (c Onvertview = = null) {return new Baseadapterhelper (context, parent, layoutid, position); }//Retrieve the existing helper and update its position baseadapterhelper Existinghelper = (baseadapterhelper) con Vertview.gettag (); Existinghelper.position = position; return existinghelper;}
In QuickAdapter , the instance is obtained by the static function of the above 5 parameters get(…) BaseAdapterHelper .
The 4 get(…) -parameter method simply passes the position by default-1. That is, the Postion method is not concerned.
Here we can control the code of the Viewholder pattern that we write in the normal way getView . In the general Viewholder mode, first infer convertView whether it is empty:
A. Suppose yes, by LayoutInflater inflate a layout file. Then create a new Viewholder storage layout in the individual sub-View, through the tag binding that Viewholder to convertView , return to our convertView ;
B. Otherwise directly get the Viewholder in tag.
Combination BaseQuickAdapter of getView(…) code. Look at the realization of the base-adapter-helper.
@Overridepublic View getView(int position, View convertView, ViewGroup parent) { if (getItemViewType(position) == 0) { final H helper = getAdapterHelper(position, convertView, parent); T item = getItem(position); helper.setAssociatedObject(item); convert(helper, item); return helper.getView(); } return createIndeterminateProgressView(convertView, parent);}
First Take getAdapterHelper(…) advantage BaseAdapterHelper of the obtained or its subclasses, for the QuickAdapter purposes of this function directly call the above BaseAdapterHelper get(…) function.
We can see that the same is first inferred whether it is convertView empty. To determine whether you need to create a new BaseAdapterHelper , or retrieve the update position from tag for reuse.
A layout is inflate in the constructor method convertView . and save the context and postion, will be convertView BaseAdapterHelper associated with through tag .
(2) Several important methods
Under normal circumstances, when we rewrite BaseQuickAdapter convert(…) , we need to get a View. At this point we are able to BaseAdapterHelper get that through its participation getView(int viewId) View . The code is as follows:
public <T extends View> T getView(int viewId) { return retrieveView(viewId);}@SuppressWarnings("unchecked")protected <T extends View> T retrieveView(int viewId) { View view = views.get(viewId); if (view == null) { view = convertView.findViewById(viewId); views.put(viewId, view); } return (T) view;}
Through ViewId to the views of the search, find then return, not found to join and return.
Views is a sparsearray. Key is view id,value for view. The child view to which the cache has been found.
Each convertView with a BaseAdapterHelper binding. Each of these BaseAdapterHelper includes an views attribute. A views convertView reference to the child View stored in the.
(3) Auxiliary method
Under normal circumstances, by getView(int viewId) getting it View , and then assigning the value will be able to.
But this library considers: since it is to get the View and then assign the value. It is better to provide some auxiliary methods for assigning values directly. So a bunch of similar code was generated setText(int viewId, String value) , and the interior was first found by ViewId and TextView then called setText(value) . Some of the code is as follows:
Public baseadapterhelper setText (int viewId, String value) {TextView view = Retrieveview (viewId); View.settext (value); return this;} Public baseadapterhelper setimageresource (int viewId, int imageresid) {...} Public baseadapterhelper setbackgroundres (int viewId, int backgroundres) {...} Public baseadapterhelper settextcolorres (int viewId, int textcolorres) {...} Public baseadapterhelper setimagedrawable (int viewId, drawable drawable) {...} Public baseadapterhelper setimageurl (int viewId, String imageUrl) {...} Public baseadapterhelper setimagebitmap (int viewId, Bitmap Bitmap) {...} @SuppressLint ("Newapi") public baseadapterhelper setalpha (int viewId, float value) {...} Public baseadapterhelper setvisible (int viewId, Boolean visible) {...} Public baseadapterhelper linkify (int viewId) {...} Public baseadapterhelper setprogress (int viewId, int progress, int max) {...} Public baseadapterhelper setrating (int viewId, float rating, int max) {...} Public baseadapterhelper settag (int viewId, int key, Object tag) {...} PubLIC baseadapterhelper setchecked (int viewId, Boolean checked) {...} Public baseadapterhelper setadapter (int viewId, Adapter Adapter) {...} ......
Implementations are based on ViewId to find the View. Then assign a value to the View code.
Just note here: setImageUrl(int viewId, String imageUrl) This method, by default is Picasso to load the picture, of course you can change into the picture you use in the project loading frame Volley,uil, etc., if you do not want to continue coupling, can refer to 1.4 缺点 the proposed modification method.
It is also possible to set up an event listener for the Sub View, some of which are as follows:
public BaseAdapterHelper setOnClickListener(int viewId, View.OnClickListener listener) { View view = retrieveView(viewId); view.setOnClickListener(listener); return this;}public BaseAdapterHelper setOnTouchListener(int viewId, View.OnTouchListener listener) {…}public BaseAdapterHelper setOnLongClickListener(int viewId, View.OnLongClickListener listener) {…}
Here are just a few of the frequently used methods, assuming that some of the control's methods are not encapsulated here. Can be BaseAdapterHelper.getView(viewId) manipulated by getting controls, or inheriting BaseAdapterHelper the implementation of their own BaseAdapterHelper .
4.4.1 Coupling Serious
(1) with Picasso coupling, want to replace with other image cache need to change the source code
Through the new interface, for the three parties themselves to the image cache library to achieve picture acquisition, or directly remove the helper.setImageUrl(…) function.
(2) Coupled with the internal join progress bar. Causes multiple types of layouts not supported
The workaround for not modifying the progress bar is given below. A better implementation should be exposed by means of an interface, for the three parties to set themselves.
Overall, the cubby is simpler. Implementation also needs to be improved.
4.2 The current plan does not support
HeaderViewListAdapter4.3 Extending multiple Item layouts
Through 3.2.1 BaseQucikAdapter.java the analysis, it can be seen that Base-adapter-helper does not support a variety of layout Item situations. Although in most cases a style is possible. But if let me write Adapter in such a simple way, suddenly a variety of layout Item of the ListView and the traditional way to write, this contrast is too big. Below we introduce. How to add multi-layout Item support on the basis of this library.
(1) Analysis
For various layouts of Item, it is clear to everyone. Need to be BaseAdapter replicated getViewTypeCount() and getItemViewType() . And you need getView() to infer it and choose a different layout file. Different layouts also need to be used differently ViewHolder .
We can be at the time of construction QucikAdapter . To set getViewTypeCount() getItemViewType() the value of and further abstract it into an interface. There are several ways to set up, assuming you need to use multiple Item layouts.
(2) Extension
Join interfaceMultiItemTypeSupport
public interface MultiItemTypeSupport<T> { int getLayoutId(int position, T t); int getViewTypeCount(); int getItemViewType(int postion, T t);}
QuickAdapter BaseQuickAdapter Add a new constructor in and to each
BaseQuickAdapterNew constructors such as the following:
protected MultiItemTypeSupport<T> multiItemSupport;public BaseQuickAdapter(Context context, ArrayList<T> data, MultiItemTypeSupport<T> multiItemSupport) { this.multiItemSupport = multiItemSupport; this.data = data == null ? new ArrayList<T>() : new ArrayList<T>(data); this.context = context;}
QuickAdapterNew constructors such as the following:
public QuickAdapter(Context context, ArrayList<T> data, MultiItemTypeSupport<T> multiItemSupport) { super(context, data, multiItemSupport);}
The same time must be BaseQuickAdapter rewritten getViewTypeCount() and getItemViewType() getView() functions.
@Overridepublic int getViewTypeCount() { return multiItemSupport != null ? (mMultiItemSupport.getViewTypeCount() + 1) : 2);}@Overridepublic int getItemViewType(int position) { if (position >= data.size()) { return 0; } return (mMultiItemSupport != null) ? mMultiItemSupport.getItemViewType(position, data.get(position)) : 1;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) { if (getItemViewType(position) == 0) { return createIndeterminateProgressView(convertView, parent); } final H helper = getAdapterHelper(position, convertView, parent); T item = getItem(position); helper.setAssociatedObject(item); convert(helper, item); return helper.getView();}
To preserve the functionality of the scroll bar that was originally provided, we made changes based on it.
BaseAdapterHelperHow to rewrite the constructor
Because of our different layouts, it must be different ViewHolder , and here BaseAdapterHelper in fact plays a ViewHolder role.
Ours BaseAdapterHelper is constructed in QuickAdapter the getAdapterHelper middle. Post-Change Code:
QuickAdapter
protected BaseAdapterHelper getAdapterHelper(int position, View convertView, ViewGroup parent) { if (mMultiItemSupport != null){ return get( context, convertView, parent, mMultiItemSupport.getLayoutId(position, data.get(position)), position); } else { return get(context, convertView, parent, layoutResId, position); }}
BaseAdapterHelpergetalso needs to be changed.
/** This method is package private and should only be used by QuickAdapter. */static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId, int position) { if (convertView == null) { return new BaseAdapterHelper(context, parent, layoutId, position); } // Retrieve the existing helper and update its position BaseAdapterHelper existingHelper = (BaseAdapterHelper)convertView .getTag(); if (existingHelper.layoutId != layoutId) { return new BaseAdapterHelper(context, parent, layoutId, position); } existingHelper.position = position; return existingHelper;}
We have stored the current LayoutID in the helper. Assume that the layoutid is inconsistent. is created once again.
(3) test
The following shows the core code
mlistview = (ListView) Findviewbyid (R.id.id_lv_main); multiitemtypesupport<chatmessage> multiitemtypesupport = new multiitemtypesupport<chatmessage> () {@ Override public int Getlayoutid (int position, Chatmessage msg) {return Msg.iscommeg ()? r.layout.main_chat_from_msg:r.layout.main_chat_send_msg; } @Override public int getviewtypecount () {return 2; } @Override public int getitemviewtype (int postion, chatmessage msg) {return Msg.iscommeg ()?
ChatMessage.RECIEVE_MSG:ChatMessage.SEND_MSG; }};initdatas (); madapter = new Quickadapter<chatmessage> (Chatactivity.this, Mdatas, Multiitemtypesupport) { @Override protected void Convert (Baseadapterhelper helper, chatmessage Item) {switch (Helper.layoutid) { Case R.layout.main_chat_from_msg:helper.settext (R.id.chat_from_content, Item.getcontent ()); Helper.settext (R.id.chat_from_name, Item.getname ()); Helper.setimageresource (R.id.chat_from_icon, Item.geticon ()); Break Case R.layout.main_chat_send_msg:helper.settext (R.id.chat_send_content, Item.getcontent ()); Helper.settext (R.id.chat_send_name, Item.getname ()); Helper.setimageresource (R.id.chat_send_icon, Item.geticon ()); Break }}};mlistview.setadapter (Madapter);
When a variety of layout Item is encountered, first construct an MultiItemTypeSupport interface object, and then in the convert basis of LayoutID. Get the different layouts to set.
Stickers:
Android Universal Adapter Base-adapter-helper Source Code Analysis