做什么玩意儿都是从需求开始做,要封装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等。下一篇,我还会写一篇用法。。。