好比一个APP的首页,包含Banner区、广告区、文本内容、图片内容、新闻内容等等。java
RecyclerView 能够用ViewType来区分不一样的item,也能够知足需求,但仍是存在一些问题,好比:面试
在item过多逻辑复杂列表界面,Adapter里面的代码量庞大,逻辑复杂,后期难以维护。
每次增长一个列表都须要增长一个Adapter,重复搬砖,效率低下。
没法复用adapter,假若有多个页面有多个type,那么就要写多个adapter。
要是有局部刷新,那么就比较麻烦了,好比广告区也是一个九宫格的RecyclerView,点击局部刷新当前数据,比较麻烦。性能优化
一般写一个多Item列表的方法服务器
主要操做步骤架构
代码以下所示ide
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){ case TYPE_BANNER: // banner 逻辑处理 break; case TYPE_AD: // 广告逻辑处理 break; case TYPE_TEXT: // 文本逻辑处理 break; case TYPE_IMAGE: //图片逻辑处理 break; case TYPE_NEW: //视频逻辑处理 break; // ... 此处省去N行代码 } } @Override public int getItemViewType(int position) { if(position == 0){ return TYPE_BANNER;//banner在开头 }else { return mData.get(position).type;//type 的值为TYPE_AD,TYPE_IMAGE,TYPE_AD,等其中一个 } } @Override public int getItemCount() { return mData == null ? 0:mData.size(); } public static class BannerViewHolder extends RecyclerView.ViewHolder{ public BannerViewHolder(View itemView) { super(itemView); //绑定控件 } } public static class NewViewHolder extends RecyclerView.ViewHolder{ public VideoViewHolder(View itemView) { super(itemView); //绑定控件 } } public static class AdViewHolder extends RecyclerView.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 RecyclerView.ViewHolder{ public ImageViewHolder(View itemView) { super(itemView); //绑定控件 } } }
上面那样写的弊端布局
核心目的就是三个性能
当列表中类型增长或减小时Adapter中主要改动的就是getItemViewType、onCreateViewHolder、onBindViewHolder这三个方法,所以,咱们就从这三个方法中开始着手。优化
既然可能存在多个type类型的view,那么能不能把这些好比banner,广告,文本,视频,新闻等当作一个HeaderView来操做。this
在getItemViewType方法中。
private ArrayList<InterItemView> headers = new ArrayList<>(); public interface InterItemView { /** * 建立view * @param parent parent * @return view */ View onCreateView(ViewGroup parent); /** * 绑定view * @param headerView headerView */ void onBindView(View headerView); } /** * 获取类型,主要做用是用来获取当前项Item(position参数)是哪一种类型的布局 * @param position 索引 * @return int */ @Deprecated @Override public final int getItemViewType(int position) { if (headers.size()!=0){ if (position<headers.size()) { return headers.get(position).hashCode(); } } if (footers.size()!=0){ int i = position - headers.size() - mObjects.size(); if (i >= 0){ return footers.get(i).hashCode(); } } return getViewType(position-headers.size()); }
onCreateViewHolder
/** * 建立viewHolder,主要做用是建立Item视图,并返回相应的ViewHolder * @param parent parent * @param viewType type类型 * @return 返回viewHolder */ @NonNull @Override public 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); return view; } } 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); return view; } } return null; }
在onBindViewHolder方法中。能够看到,在此方法中,添加一种header类型的view,则经过onBindView进行数据绑定。
/** * 绑定viewHolder,主要做用是绑定数据到正确的Item视图上。当视图从不可见到可见的时候,会调用这个方法。 * @param holder holder * @param position 索引 */ @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()); } 如何使用,以下所示,这个就是banner类型,能够说是解耦了以前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);
封装后好处