RecyclerViewAdapter封装(上)

做什么玩意儿都是从需求开始做,要封装RecyclerViewAdapter,首先我们就得明白为什么要封装它,,不过这好像都是废话,肯定是为了更好用。。。but,要不是在实际需求中一步步遇到各种问题,是不会封装的更好的。

来一个实际案例,一步步的明白我们封装的意义何在。

公司要开发一个在线商店,所以90%的APP功能是在RecyclerView中展示商品,版本1.0中需要展示商品的同时还要对特殊的商品进行特殊展示。我们使用AccessoiresAdapter作为商品展示的Adapter,当然里边需要两种布局,一种布局是特殊商品展示的布局,一种是普通商品展示的布局,item_accessory_offer.xml作为特殊商品的布局 item_accessory.xml作为普通商品的布局,根据两种viewType的类型,去分别显示不同的商品,因此AccessoiresAdapter的代码如下:

public class AccessoiresAdapter extends RecyclerView.Adapter {

  final int VIEW_TYPE_ACCESSORY = 0;
  final int VIEW_TYPE_ACCESSORY_SPECIAL_OFFER = 1;

  List<Accessory> items;

  @Override public int getItemViewType(int position) {
     Accessory accessory = items.get(postion);
     if (accessory.hasSpecialOffer()){
       return VIEW_TYPE_ACCESSORY_SPECIAL_OFFER;
     } else {
       return VIEW_TYPE_ACCESSORY;
     }
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (VIEW_TYPE_ACCESSORY_SPECIAL_OFFER == viewType){
      return new SpecialOfferAccessoryViewHolder(inflater.inflate(R.layout.item_accessory_offer, parent));
    } else {
      return new AccessoryViewHolder (inflater.inflate(R.layout.item_accessory)):
    }
  }

  ...

}
   OK,一切完美,1.0的版本很快就发布了。
   随着用户的增长,APP也需要完成更多的功能,现在老板要求需要我需要有一个抢购的商品显示在商品列表中,当然,我们需要一种商品抢购的布局,要显示在商品列表中,我们可以修改我们的 AccessoiresAdapter,当然也可以继承这个Adapter来进行修改处理。 因此我们定义一个HomeAdapter继承AccessoiresAdapter来展示所需要的商品列表,同时我们

public class HomeAdapter extends AccessoriesAdapter {

  final int VIEW_TYP_NEWS_TEASER = 2;

  @Override public int getItemViewType(int position) {
     if (items.get(position) instanceof NewsTeaser){
       return VIEW_TYP_NEWS_TEASER;
     } else {
       // accessories and special offers
       return super.getItemViewType(position);
     }
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (VIEW_TYP_NEWS_TEASER == viewType){
      return new NewsTeaserItem( inflater.inflate(R.layout.item_news_teaser, parent));
    } else {
      // accessories and special offers
      return super.onCreateViewHolder(parent, viewType);
    }
  }

  ...
}
  我们同时需要一个服务商的页面,展示商品的供货商,因此定义需要再定义一个 ServerAdapter

public class ServerAdapter extends RecyclerView.Adapter {

  final int VIEW_TYP_FOOD_TIP = 0;

  @Override public int getItemViewType(int position) {
     return VIEW_TYP_FOOD_TIP;
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new PetFoodViewHolder(inflater.inflate(R.layout.item_pet_food, parent))
  }

  ...

}
OK,还算轻松,很快2.0版本发布。

又过了一段时间,Boss说,咱们这个APP现在还没有盈利,为了实现盈利,已经和一些广告公司签订了合同,在APP中和商品,服务商等列表一起来展示他们的广告,并尽快发布新的版本,好吧。。。AdvertismentAdapter:

public class AdvertismentAdapter extends RecyclerView.Adapter {

  final int VIEW_TYP_ADVERTISEMENT = 0;

  @Override public int getItemViewType(int position) {
     return VIEW_TYP_ADVERTISEMENT;
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return new AdvertismentViewHolder(inflater.inflate(R.layout.item_advertisment, parent))
  }

  ...

}
然后,改造所有的Adapter,需要继承这个 AdvertismentAdapter ,(谁让人家有钱,要在各个列表中都显示呢。。)

AccessoiresAdapter extends AdvertisementAdapter

HomeAdapter extends AccessoiresAdapter extends AdvertisementAdapter

ServerAdapter extends AdvertisementAdapter

OK,处理完成,3.0版本发布。

又过了一段时间,Boss找你说,这个3.0版本上线应用商店以后,由于大量的广告,遭受了很多的差评,用户流失严重,去掉广告?不可能,签订的合同还没到期,做法就是再重新弄一个APP,里边没有广告。然后Boss让你在很短的时间赶出这个APP来能不能,想了想,应该是没有问题的,毕竟只是去广告而且布局什么的都已经在以前的APP中了,只需要复制过来就可以了。

但是,现在来看,,所有的Adapter都是继承AdvertisementAdapter,要想去掉,改动很大,多个Adapter类似,却没有可以复用的Adapter ,都是多继承的关系。我们的原则是:组成要高于继承(Favor composition over inheritance),是不是可以像积木那样,所有的组件都是分离的,需要什么拿过来就可以。

好,现在我们需要定义两个代表类,一个显示商品类AccessoiresAdapterDelegate 还有一个显示显示服务商类 ServerAdapterDelegate

public class AccessoiresAdapterDelegate{

  private int viewType;

  public <span style="font-size: 15.2px; line-height: 16.72px; font-family: Consolas, "Liberation Mono", Courier, monospace;">AccessoiresAdapterDelegate</span>(int viewType){
    this.viewType = viewType;
  }

  public int getViewType(){
    return viewType;
  }

  public boolean isForViewType(List items, int position) {
    return  items.get(position) instanceof Accessoir;
  }

  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
    return new AccessoirViewHolder(inflater.inflate(R.layout.item_news_teaser, parent, false));
  }

  public void onBindViewHolder(List items, int position, RecyclerView.ViewHolder holder) {
      Accessoir = (Accessoir) items.get(position);
      AccessoirViewHolder vh = (<span style="font-size: 15.2px; line-height: 16.72px; font-family: Consolas, "Liberation Mono", Courier, monospace;">AccessoirViewHolder</span>) vh;

      vh.title.setText(teaser.getTitle());
      vh.text.setText(teaser.getText());
  }
}

public class <span style="font-family: Consolas, "Liberation Mono", Courier, monospace; font-size: 15.2px; line-height: 16.72px;">ServerAdapterDelegate</span>{

  private int viewType;

  public ServerAdapterDelegate(int viewType){
    this.viewType = viewType;
  }

  public int getViewType(){
    return viewType;
  }

  public boolean isForViewType(List items, int position) {
    return  items.get(position) instanceof ServerTip;
  }

  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
    return new ServerTipViewHolder(inflater.inflate(R.layout.item_pet_food, parent, false));
  }

  public void onBindViewHolder(List items, int position, RecyclerView.ViewHolder holder) {
      ServerTip tip = (ServerTip) items.get(position);
      ServerTipViewHolder vh = (ServerTipViewHolder) vh;

      vh.image.setImageRes(tip.getImage());
      vh.text.setText(tip.getText());
  }
}
定义我们的Adapter

public class ShopAdapter extends RecyclerView.Adapter{

  final int VIEW_TYP_ACCESSOIRS = 0;
  final int VIEW_TYP_SERVER = 1;

  
  AccessoiresAdapterDelegate accessoiredDelegate;
  ServerAdapterDelegate serverDelegate;

  List items;

  public ShopAdapter(){
    
    accessoiredDelegate= new AccessoiresAdapterDelegate(VIEW_TYP_ACCESSOIRS);
    serverDelegate = new ServerAdapterDelegate(VIEW_TYP_SERVER);
  }

  @Override public int getItemViewType(int position) {
     if (accessoiredDelegate.isForViewType(items, position)){
       return accessoiredDelegate.getViewType();
     }
     else if (serverDelegate.isForViewType(items, position)){
       return serverDelegate.getViewType();
     }

     throw new IllegalArgumentException("No delegate found");
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    if (accessoiredDelegate.getViewType() == viewType){
      return accessoiredDelegate.onCreateViewHolder(parent);
    }
    else if (serverDelegate.getViewType() == viewType){
      return serverDelegate.onCreateViewHolder(parent);
    }

    throw new IllegalArgumentException("No delegate found");
  }


  @Override public void onBindViewHolder(VH holder, int position){
    int viewType = holder.getViewType();
    if (accessoiredDelegate.getViewType() == viewType){
      accessoiredDelegate.onBindViewHolder(items, position, holder);
    }
    else if (serverDelegate.getViewType == viewType){
      serverDelegate.onBindViewHolder(items, position, holder);
    }
  }
}


通过以上,大概你已经看了出来,我们完全可以定义一个视图的接口类,然后定义一个管理视图的接口类。

/**
 * @param <T> the type of adapters data source i.e. List<Accessory>
 */
public interface AdapterDelegate<T> {

  /**
   * Called to determine whether this AdapterDelegate is the responsible for the given data
   * element.
   *
   * @param items The data source of the Adapter
   * @param position The position in the datasource
   * @return true, if this item is responsible,  otherwise false
   */
  public boolean isForViewType(@NonNull T items, int position);

  /**
   * Creates the  {@link RecyclerView.ViewHolder} for the given data source item
   *
   * @param parent The ViewGroup parent of the given datasource
   * @return The new instantiated {@link RecyclerView.ViewHolder}
   */
  @NonNull public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent);

  /**
   * Called to bind the {@link RecyclerView.ViewHolder} to the item of the datas source set
   *
   * @param items The data source
   * @param position The position in the datasource
   * @param holder The {@link RecyclerView.ViewHolder} to bind
   */
  public void onBindViewHolder(@NonNull T items, int position, @NonNull RecyclerView.ViewHolder holder);
}

public class AdapterDelegatesManager<T> {

  public AdapterDelegatesManager<T> addDelegate(@NonNull AdapterDelegate<T> delegate) {
    ...
  }

  public int getItemViewType(@NonNull T items, int position) {
    ...
  }

  public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    ...
  }

  public void onBindViewHolder(@NonNull T items, int position, @NonNull RecyclerView.ViewHolder viewHolder) {
    ...
  }
}

然后我们就可以在Adapter中,我们可以将所需的视图,注册到Manager管理类中,通过管理类调用相应的视图逻辑。

public class NewsTipAdapter extends RecyclerView.Adapter{

  final int VIEW_TYP_NEWS_TEASER = 0;
  final int VIEW_TYP_FOOD_TIP = 1;

  List items;

  AdapterDelegatesManager delegates = new AdapterDelegatesManager();

  public NewsTipAdapter(){
    delegates.add(new NewsTeaserAdapterDelegate()); // Assigns internally ViewType integer
    delegates.add(new PetFoodTipAdapterDelegate());
  }

  @Override public int getItemViewType(int position) {
     return delegates.getItemViewType(items, position);
  }

  @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    return delegates.onCreateViewHolder(parent, viewType);
  }

  @Override public void onBindViewHolder(VH holder, int position){
      delegates.onBindViewHolder(items, position, holder);
  }
}

好了,这就是项目的经历,现在可以以极少的代码轻松的添加视图了。

这个是我项目的地址:传送门

可以实现添加头布局,加载更多,多ItemView等。下一篇,我还会写一篇用法。。。








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RecyclerView.Adapter 是一个用于管理 RecyclerView 中数据和视图的基类。它有三个主要的方法:onCreateViewHolder、onBindViewHolder 和 getItemCount。 onCreateViewHolder 方法用于创建 ViewHolder 对象,ViewHolder 对象用于保存 RecyclerView 中的视图。onBindViewHolder 方法用于将数据绑定到 ViewHolder 中的视图上。getItemCount 方法用于返回 RecyclerView 中的数据项数量。 在实现 RecyclerView.Adapter 时,我们需要重写这三个方法,并根据实际需求进行相应的处理。此外,我们还可以添加一些其他的方法,例如添加、删除、更新数据等。 下面是一个简单的 RecyclerView.Adapter 实现示例: ``` public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { private List<String> mData; public MyAdapter(List<String> data) { mData = data; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { String data = mData.get(position); holder.mTextView.setText(data); } @Override public int getItemCount() { return mData.size(); } public static class ViewHolder extends RecyclerView.ViewHolder { public TextView mTextView; public ViewHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.text_view); } } } ``` 在这个示例中,我们创建了一个 MyAdapter 类,它继承自 RecyclerView.Adapter。在构造函数中,我们传入了一个数据列表 mData。在 onCreateViewHolder 方法中,我们使用 LayoutInflater 创建了一个视图,并将其封装在 ViewHolder 中返回。在 onBindViewHolder 方法中,我们将数据绑定到 ViewHolder 中的视图上。在 getItemCount 方法中,我们返回 mData 的大小。 这是一个简单的 RecyclerView.Adapter 实现示例,实际应用中可能需要更复杂的处理逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值