Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Concat Adapters Droidcon APAC 2020

Abhishesh
December 15, 2020

Concat Adapters Droidcon APAC 2020

ConcatAdapter is a new api exposed in recycler view which enables us to sequentially combine multiple adapters.
Learn how to better encapsulate your adapters having different data sources.
Different use cases where concat adapter can be used in an easy & elegant way.

Abhishesh

December 15, 2020
Tweet

More Decks by Abhishesh

Other Decks in Technology

Transcript

  1. Concat adapters: Easy & elegant way of combining adapters Abhishesh

    Srivastava https://twitter.com/abhishesh_sri https://github.com/abhishesh-srivastava
  2. Too simple. Isn’t it? class WowAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() { …

    override fun getItemViewType(position: Int): Int { if (position == 0) { return VIEW_TYPE_HEADER_1 } return VIEW_TYPE_DATA_SOURCE_1 } … }
  3. I know my game very well!!! class MessAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()

    { … override fun getItemViewType(position: Int): Int { if (position == 0) { return VIEW_TYPE_HEADER_1 } else if (position < dataSource1.size) { return VIEW_TYPE_DATA_SOURCE_1 } else if (position == dataSource1.size + 1) { return VIEW_TYPE_HEADER_2 } else { return VIEW_TYPE_DATA_SOURCE_2; } } … }
  4. Hold on hold on. I will figure something out class

    HellAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() { … override fun getItemViewType(position: Int): Int { if (position == 0) { return VIEW_TYPE_HEADER_1 } else if (position < dataSource1.size) { return VIEW_TYPE_DATA_SOURCE_1 } else if (position == dataSource1.size + 1) { return VIEW_TYPE_HEADER_3 } else if (position < (dataSource1.size + dataSource3.size)) { return VIEW_TYPE_DATA_SOURCE_3 } else if (position == dataSource1.size + dataSource2.size) { return VIEW_TYPE_HEADER_2 } else { return VIEW_TYPE_DATA_SOURCE_2 } } … }
  5. Refactor? class HellAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() { … override fun getItemViewType(position:

    Int): Int { if (position == 0) { return VIEW_TYPE_HEADER_1 } else if (position < dataSource1.size) { return VIEW_TYPE_DATA_SOURCE_1 } else if (position == dataSource1.size + 1) { return VIEW_TYPE_HEADER_3 } else if (position < (dataSource1.size + dataSource3.size)) { return VIEW_TYPE_DATA_SOURCE_3 } else if (position == dataSource1.size + dataSource2.size) { return VIEW_TYPE_HEADER_2 } else { return VIEW_TYPE_DATA_SOURCE_2 } } … }
  6. Solution Let’s have our AHA(Android Has an Abstraction) moment Concat

    adapters to the rescue Alternatives : Epoxy, Bento
  7. Concat adapters • Added in recyclerview 1.2.0-alpha02 as MergeAdapter •

    Renamed to ConcatAdapter in 1.2.0-alpha04 • Presents content of multiple adapters in sequence
  8. Why? • Encapsulate adapters rathers than merging data source and

    adapter into one. • Less error-prone. • Code reusability • Reduced code complexity
  9. Concat adapter way!! val adapter1: AwesomeAdapter = ... val adapter2:

    GreatAdapter = ... val adapter3: SingleResponsibilityAdapter = ... val concatenated: ConcatAdapter = ConcatAdapter(adapter1, adapter2, adapter3); recyclerView.setAdapter(concatenated);
  10. API public boolean addAdapter(int index, @NonNull Adapter<? extends ViewHolder> adapter)

    { } public boolean removeAdapter(@NonNull Adapter<? extends ViewHolder> adapter) { }
  11. API public boolean addAdapter(int index, @NonNull Adapter<? extends ViewHolder> adapter)

    { } Adds an adapter at specified index. Note: It’s not the recyclerview adapter
  12. API public static final Config DEFAULT = new Config(true, NO_STABLE_IDS);

    public ConcatAdapter(@NonNull List<? extends Adapter<? extends ViewHolder>> adapters) { this(Config.DEFAULT, adapters); } public ConcatAdapter( @NonNull Config config, @NonNull List<? extends Adapter<? extends ViewHolder>> adapters) { }
  13. ConcatAdapter.Config Config(boolean isolateViewTypes, @NonNull StableIdMode stableIdMode) { } NO_STABLE_IDS: Default.

    Individual adapters stable id would be ignored. ISOLATED_STABLE_IDS: Individual adapters to have stable ids. SHARED_STABLE_IDS: Child adapters should never report the same stable id.
  14. notifyDataSetChanged() public abstract static class Adapter<VH extends ViewHolder> { ...

    public final void notifyDataSetChanged() { mObservable.notifyChanged(); } public abstract static class AdapterDataObserver { ... @Override public void onChanged(@NonNull NestedAdapterWrapper wrapper) { mConcatAdapter.notifyDataSetChanged(); calculateAndUpdateStateRestorationPolicy(); } … }
  15. Q&A