smart-recycler-adapter

Never code any boilerplate RecyclerAdapter again!
This library will make it easy and painless to map your data item with a target ViewHolder.

smart-recycler-adapter

Gradle

Step 1. Add the JitPack repository to your build file

allprojects {
  repositories {
    maven { url 'https://jitpack.io' }
  }
}  
Groovy

Step 2. Add the dependency

dependencies {  
  implementation 'com.github.manneohlund:smart-recycler-adapter:2.0.1'
}
Groovy

New complex SmartRecyclerAdapter v2.0.0

New in SmartRecyclerAdapter v2.0.0 is support for nested recycler adapter.
Now you can easily build complex nested adapters without hustle and have full control of the adapter in your view controlling Fragment or Activity.
Use the new create() method instead of the into(recyclerView) to create just the SmartRecyclerAdapter then set the adapter to the recycler view in your ViewHolder.
Just implement the SmartAdapterHolder interface in your ViewHolder and SmartRecyclerAdapter will handle the mapping.

1. Create your nested SmartRecyclerAdapter

SmartRecyclerAdapter myWatchListSmartMovieAdapter = SmartRecyclerAdapter
  .items(myWatchListItems)
  .map(MovieModel.class, ThumbViewHolder.class)
  .addViewEventListener(
    ThumbViewHolder.class,
    R.id.action_on_click,
    (view, actionId, position) -> playMovie())
  .create();
Java

2. Map myWatchListSmartMovieAdapter with MyWatchListViewHolder

SmartRecyclerAdapter
  .items(items)
  .map(MoviePosterModel.class, PosterViewHolder.class)
  .map(MyWatchListModel.class, MyWatchListViewHolder.class)
  .map(MyWatchListViewHolder.class, myWatchListSmartMovieAdapter)
  .into(recyclerView);
Java

3. Map myWatchListSmartMovieAdapter to MyWatchListViewHolder

class MyWatchListViewHolder
        extends SmartAutoEventViewHolder<MyWatchListModel>
        implements SmartAdapterHolder {
    
    // Constructor here
    
    @Override
    public void setSmartRecyclerAdapter(SmartRecyclerAdapter smartRecyclerAdapter) {
        recyclerView.setLayoutManager(LinearLayoutManager(recyclerView.context, HORIZONTAL, false);
        recyclerView.adapter = (RecyclerView.Adapter) smartRecyclerAdapter;
    }

    public void bind(MyWatchListModel myWatchListModel) {
        // bind model data to views
    }
}
Java

Basic

Basic adapter creation

SmartRecyclerAdapter
  .items(items)
  .map(MoviePosterModel.class, PosterViewHolder.class)
  .map(MovieBannerModel.class, BannerViewHolder.class)
  .map(TopNewsModel.class, TopNewsViewHolder.class)
  .into(recyclerView);
Java

ViewHolder

Just extend your ViewHolder class with SmartViewHolder and pass in the target type ex SmartViewHolder<Mail>.
Note that the constructor must take ViewGroup as parameter, in this case PosterViewHolder(ViewGroup parentView).
The parentView is the recyclerView.

Works with Android DataBinding! Just add the DataBinding LayoutInflater in super call. ?
public class PosterViewHolder extends SmartViewHolder<MoviePosterModel> {

  public PostViewHolder(ViewGroup parentView) { 
    super(LayoutInflater.from(parentView.getContext()).inflate(R.layout.poster_view, parentView, false)); 
  }
  
  @Override 
  public void bind(MoviePosterModel model) {
    Glide.with(imageView)
      .load(model.icon)
      .into(imageView);
  }
} 
Java

View event listener

You can easily assign events to views and add an ViewEventListener to the SmartRecyclerAdapter for easy handling.

You must extend your ViewHolder with SmartEventViewHolder.

SmartRecyclerAdapter
  .items(items)
  .map(MovieModel.class, MovieViewHolder.class)
  // You need to define your own view event listeners like onClickListener on a view
  .addViewEventListener((view, actionId, position) -> handleItemEvent())
  // Adds event listener for MovieViewHolder only
  .addViewEventListener(MovieViewHolder.class, (view, actionId, position) -> handleItemEvent())
  .into(recyclerView);
Java

In your view holder, add eg OnClickListener to a view and call notifyOnItemEvent.

Your ViewHolder must extend SmartEventViewHolder.

class MovieViewHolder extends SmartEventViewHolder<MovieModel> {
    @Override
    public void bind(MovieModel movieModel) {
      imageView.setOnClickListener(view -> notifyOnItemEvent(view, R.id.action_play_movie));
    }
}
Java

If you are lazy and want to auto assign a predefined onClickListener and onLongClickListener with actionIds R.id.action_on_click and R.id.action_on_long_click,
just extend your ViewHolder with SmartAutoEventViewHolder.

class MovieViewHolder extends SmartAutoEventViewHolder<MovieModel>
Java

And add event listener to SmartRecyclerAdapter builder.

SmartRecyclerAdapter
  .items(items)
  .map(MovieModel.class, MovieViewHolder.class)
  /// Adds event listener for MovieViewHolder and adds View.OnClickListener with action R.id.action_on_click on view with id R.id.info_button
  .addViewEventListener(MovieViewHolder.class,
                        R.id.info_button, 
                        R.id.action_on_click, 
                        (view, actionId, position) -> openMovieInfo())
  .into(recyclerView);
Java

Adapter creation with ViewTypeResolver

If you want to bind one data type with different view holders depending on some attribute you can set a ViewTypeResolver.
Note .map() call not needed in this case but you can combine if you want to.
You can also set an OnViewDetachedFromWindowListener for immediate view holder detach handling.

SmartRecyclerAdapter
  .items(items)
  .setViewTypeResolver((item, position) -> {
    if (item instanceof MovieTrailerModel) { 
      return MovieTrailerViewHolder.class;
    } else if (item instanceof MovieModel && ((MovieModel)item).isRatedR()) { 
      return RMovieViewHolder.class; 
    } return MovieViewHolder.class; // Add default view if needed, else SmartRecyclerAdapter will look at the base `.map` mapping
  })
  .setOnViewDetachedFromWindowListener(holder -> {
    if (holder instanceof ImageViewHolder) {
      ImageCacheManager.getInstance().cancelAsyncTask(holder);
    }
  })
  .into(recyclerView);
Java

More SmartRecyclerAdapter features

SmartRecyclerAdapter adapter = SmartRecyclerAdapter
        .items(items)
        .map(MovieModel.class, MovieViewHolder.class)
        .into(recyclerView);

// We can add more data
adapter.addItems(items);

// Add data at index with animation
adapter.addItem(0, item);

// Add data at index without animation
adapter.addItem(0, item, false);

// Remove item at index with animation
adapter.removeItem(0);

// Remove item at index without animation
adapter.removeItem(0, false);

// Replace item at index with animation
adapter.replaceItem(0, item);

// Replace item at index without animation
adapter.replaceItem(0, item, false);

// Get items by type
adapter.getItems(MovieModel.class);

// Delete all items in the list
adapter.clear();
Java

GitHub