catalogue
- 01. Look at the actual needs first
- 02. Adapter implements multiple types
- The disadvantages of writing this way
- 04. How to gracefully implement Adapter encapsulation
Make yourself a date
- Personal dating information: juejin.cn/post/684490…
Good news
- Summary of blog notes [March 2016 to present], including Java basic and in-depth knowledge points, Android technology blog, Python learning notes, etc., including the summary of bugs encountered in daily development, of course, I also collected a lot of interview questions in my spare time, updated, maintained and corrected for a long time, and continued to improve… Open source files are in Markdown format! At the same time, ALSO open source life blog, from 12 years, accumulated a total of N [nearly 1 million words, gradually moved to the Internet], reprint please indicate the source, thank you!
- Link address:Github.com/yangchong21…
- If you feel good, you can star, thank you! Of course, also welcome to put forward suggestions, everything starts from small, quantitative change causes qualitative change!
01. Look at the actual needs first
- For example, the home page of an APP contains Banner area, advertising area, text content, picture content, news content and so on.
- RecyclerView can use ViewType to distinguish different items, and can also meet the needs, but there are still some problems, such as:
- 1. In the interface of the list of too many items and complicated logic, there is a large amount of code in the Adapter, which is difficult to maintain in the later stage.
- 2. Each time a list is added, an Adapter needs to be added, which is inefficient to move bricks repeatedly.
- If you have multiple pages with multiple types, you need to write multiple adapters.
- 4, if there is local refresh, then it is more troublesome, for example, the advertising area is also a nine-grid RecyclerView, click local refresh the current data, more troublesome.
02. Adapter implements multiple types
- The usual way to write a multi-item list
- Handling different items for different viewTypes can be a lot of code if logic is complex. If new requirements are added in version iterations, it is cumbersome to modify the code and difficult to maintain later.
- Main Operation Steps
- Determine the ViewHolder type to be created in onCreateViewHolder based on the return value of the viewType parameter, getItemViewType
- The onBindViewHolder method is used to determine the specific type of ViewHolder and bind data and logic for different types of ViewHolder
- The code is shown below
public class HomePageAdapter extends RecyclerView.Adapter { public static final int TYPE_BANNER = 0; public static final int TYPE_AD = 1; public static final int TYPE_TEXT = 2; public static final int TYPE_IMAGE = 3; public static final int TYPE_NEW = 4; private List<HomePageEntry> mData; public void setData(List<HomePageEntry> data) { mData = data; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType){ case TYPE_BANNER: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_banner_layout,null)); case TYPE_AD: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_ad_item_layout,null)); case TYPE_TEXT: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_text_item_layout,null)); case TYPE_IMAGE: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_image_item_layout,null)); case TYPE_NEW: return new BannerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.home_news_item_layout,null)); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int type = getItemViewType(position); switch (type) {caseTYPE_BANNER: // Banner logic processingbreak; caseTYPE_AD: // Advertising logic processingbreak; caseTYPE_TEXT: // Text logic processingbreak; caseTYPE_IMAGE: // Image logic processingbreak; caseTYPE_NEW: // Video logic processingbreak; / /... Override public int getItemViewType(int position) {if(position == 0){ returnTYPE_BANNER; //banner at the beginning}else { returnmData.get(position).type; //type}} @override public intgetItemCount() { returnmData == null ? 0:mData.size(); } public static class BannerViewHolder extends RecyclerView.ViewHolder{ public BannerViewHolder(View itemView) { super(itemView); }} public static class extends RecyrecyView. ViewHolder{public VideoViewHolder(View itemView) { super(itemView); }} public static class extends recyrecyView. ViewHolder{public AdViewHolder(View itemView) { super(itemView); }} public static class TextViewHolder extends recyclerView. ViewHolder{public TextViewHolder(View itemView) { super(itemView); }} public static class ImageViewHolder extends recyview. ViewHolder{public ImageViewHolder(View itemView) { super(itemView); // Bind control}}}Copy the code
The disadvantages of writing this way
- The downside of that
- Type checking and type transformation. Since different ViewHolder types are created in onCreateViewHolder, data binding and logic processing should be performed in onBindViewHolder for different ViewHolder types. This results in the need to type check and cast ViewHolder via Instanceof.
- The current requirement is that there are five layout class types in the list, so if the requirement changes, the extreme case is that the data source is fetched from the server, and the Model in the data determines the layout type in the list. In this case, every time the model changes or the model type increases, we have to change a lot of code in the Adapter, and the Adapter must know the position of a particular model in the list unless it is agreed with the server, which is obviously not realistic.
- As the layout type in the list increases and changes, the code in getItemViewType, onCreateViewHolder, and onBindViewHolder all need to be changed or increased. The code in the Adapter becomes bloated and messy. Increased code maintenance costs.
04. How to gracefully implement Adapter encapsulation
- There are three core purposes
- Avoid type checking and type transitions for classes
- Enhance Adapter scalability
- Enhance Adapter maintainability
- GetItemViewType, onCreateViewHolder, and onBindViewHolder are the three main methods that change in Adapter as the types in the list increase or decrease, so we’ll start with them.
- Since there may be multiple views of type, can we treat them like banners, ads, text, video, news, etc. as a HeaderView?
- In the getItemViewType method.
- Simplify code by reducing logic judgments like if, and simply add type with hashCode.
- By creating the layout type of the list, instead of simply identifying the layout type, you return the layout’s hashCode value
private ArrayList<InterItemView> headers = new ArrayList<>(); Public interface InterItemView {/** * create view * @parent parent * @returnview */ View onCreateView(ViewGroup parent); /** * bind view * @param headerView headerView */ void onBindView(view headerView); } /** * get type, mainly used to get what type of layout the current Item(position argument) is * @param position index * @return int */ @Deprecated @Override public final int getItemViewType(int position) { if(headers.size()! = 0) {if (position<headers.size()) { returnheaders.get(position).hashCode(); }}if(footers.size()! =0){ int i = position - headers.size() - mObjects.size();if (i >= 0){ returnfooters.get(i).hashCode(); }}return getViewType(position-headers.size()); } Copy the code
- onCreateViewHolder
- GetItemViewType returns the layout hashCode value, the viewType in the onCreateViewHolder(ViewGroup parent, int viewType) argument
/** * Create viewHolder, which creates the Item view and returns the corresponding viewHolder * @param parent parent * @param viewTypetypeType * @returnPublic Final BaseViewHolder onCreateViewHolder(@nonnull ViewGroup parent) int viewType) { View view = createViewByType(parent, viewType);if(view! =null){return new BaseViewHolder(view); } final BaseViewHolder viewHolder = OnCreateViewHolder(parent, viewType); setOnClickListener(viewHolder); return viewHolder; } private View createViewByType(ViewGroup parent, int viewType){ for (InterItemView headerView : headers){ if (headerView.hashCode() == viewType){ View view = headerView.onCreateView(parent); StaggeredGridLayoutManager.LayoutParams layoutParams; if(view.getLayoutParams()! =null) { layoutParams = new StaggeredGridLayoutManager.LayoutParams(view.getLayoutParams()); }else { layoutParams = new StaggeredGridLayoutManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } layoutParams.setFullSpan(true); view.setLayoutParams(layoutParams); returnview; }}for (InterItemView footerView : footers){ if (footerView.hashCode() == viewType){ View view = footerView.onCreateView(parent); StaggeredGridLayoutManager.LayoutParams layoutParams; if(view.getLayoutParams()! =null) { layoutParams = new StaggeredGridLayoutManager.LayoutParams(view.getLayoutParams()); }else { layoutParams = new StaggeredGridLayoutManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } layoutParams.setFullSpan(true); view.setLayoutParams(layoutParams); returnview; }}return null; } Copy the code
- In the onBindViewHolder method. As you can see, in this method, you add a view of type header, and the data binding is done via onBindView.
/** * Bind viewHolder to bind data to the correct Item view. This method is called when the view is never visible. @override public final void onBindViewHolder(BaseViewHolder holder) int position) { holder.itemView.setId(position);if(headers.size()! =0 && position<headers.size()){ headers.get(position).onBindView(holder.itemView);return ; } int i = position - headers.size() - mObjects.size(); if(footers.size()! =0 && i>=0){ footers.get(i).onBindView(holder.itemView);return ; } OnBindViewHolder(holder,position-headers.size()); } Copy the code
- How to use this, as shown below, is the banner type, which decouples the complex operations of the previous Adapter
InterItemView interItemView = new InterItemView() { @Override public View onCreateView(ViewGroup parent) { BannerView header = new BannerView(HeaderFooterActivity.this); header.setHintView(new ColorPointHintView(HeaderFooterActivity.this, Color.YELLOW, Color.GRAY)); header.setHintPadding(0, 0, 0, (int) AppUtils.convertDpToPixel( 8, HeaderFooterActivity.this)); header.setPlayDelay(2000); header.setLayoutParams(new RecyclerView.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, (int) AppUtils.convertDpToPixel(200, HeaderFooterActivity.this))); header.setAdapter(new BannerAdapter(HeaderFooterActivity.this)); return header; } @Override public void onBindView(View headerView) { } }; adapter.addHeader(interItemView); Copy the code
- Post-package benefits
- Extensibility – The Adapter does not care about the position of different list types in the list, so list types can be added or subtracted at will for the Adapter. Conveniently, the layout and data binding of the setting type View are not handled in adapter. Fully decoupled.
- Maintainability – Different list types are processed by Adapter to add headerView. Even if multiple headerViews are added, they do not interfere with each other. The code is simple and the maintenance cost is low.
The other is introduced
01. About blog summary links
- 1. Tech blog round-up
- 2. Open source project summary
- 3. Life Blog Summary
- 4. Himalayan audio summary
- 5. Other summaries
02. About my blog
- My personal website: www.yczbj.org, www.ycbjie.cn
- Github:github.com/yangchong21…
- Zhihu: www.zhihu.com/people/yczb…
- Jane: www.jianshu.com/u/b7b2c6ed9…
- csdn:my.csdn.net/m0_37700275
- The Himalayan listening: www.ximalaya.com/zhubo/71989…
- Source: China my.oschina.net/zbj1618/blo…
- Soak in the days of online: www.jcodecraeer.com/member/cont.
- Email address: [email protected]
- Blog: ali cloud yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV
- Segmentfault headline: segmentfault.com/u/xiangjian…
- The Denver nuggets: juejin. Cn/user / 197877…