From 0823d28322f06dc386e39558427bebd40fe5cafa Mon Sep 17 00:00:00 2001 From: Vivchar Vitaly Date: Mon, 20 Mar 2017 12:18:03 +0700 Subject: [PATCH] add DiffUtil support, update gradle dependencies --- .idea/misc.xml | 2 +- example/build.gradle | 7 +- .../immutableadapter/MainActivity.java | 110 ++++++++++++++++-- .../immutableadapter/items/BaseItemModel.java | 12 ++ .../items/category/CategoryModel.java | 41 ++++++- .../items/content/ContentModel.java | 42 ++++++- .../items/header/HeaderModel.java | 41 ++++++- example/src/main/res/layout/main.xml | 24 ++-- rendererrecyclerviewadapter/build.gradle | 6 +- .../RendererRecyclerViewAdapter.java | 26 +++++ 10 files changed, 277 insertions(+), 34 deletions(-) create mode 100644 example/src/main/java/com/github/vivchar/immutableadapter/items/BaseItemModel.java diff --git a/.idea/misc.xml b/.idea/misc.xml index b28cefd..264e400 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -53,7 +53,7 @@ - + diff --git a/example/build.gradle b/example/build.gradle index dcb4ce4..0cb7d0e 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -24,9 +24,10 @@ dependencies { androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:appcompat-v7:25.1.1' - compile "com.android.support:cardview-v7:25.1.1" - compile "com.android.support:percent:25.1.1" + compile 'com.android.support:appcompat-v7:25.3.0' + compile "com.android.support:cardview-v7:25.3.0" + compile "com.android.support:percent:25.3.0" + compile 'com.android.support:design:25.3.0' testCompile 'junit:junit:4.12' compile project(path: ':rendererrecyclerviewadapter') } diff --git a/example/src/main/java/com/github/vivchar/immutableadapter/MainActivity.java b/example/src/main/java/com/github/vivchar/immutableadapter/MainActivity.java index ab42043..4302e7f 100644 --- a/example/src/main/java/com/github/vivchar/immutableadapter/MainActivity.java +++ b/example/src/main/java/com/github/vivchar/immutableadapter/MainActivity.java @@ -2,21 +2,26 @@ import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.widget.Toast; -import com.github.vivchar.immutableadapter.items.content.ContentModel; -import com.github.vivchar.immutableadapter.items.content.ContentViewRenderer; +import com.github.vivchar.immutableadapter.items.BaseItemModel; import com.github.vivchar.immutableadapter.items.category.CategoryModel; import com.github.vivchar.immutableadapter.items.category.CategoryViewRenderer; +import com.github.vivchar.immutableadapter.items.content.ContentModel; +import com.github.vivchar.immutableadapter.items.content.ContentViewRenderer; import com.github.vivchar.immutableadapter.items.header.HeaderModel; import com.github.vivchar.immutableadapter.items.header.HeaderViewRenderer; import com.github.vivchar.rendererrecyclerviewadapter.ItemModel; import com.github.vivchar.rendererrecyclerviewadapter.RendererRecyclerViewAdapter; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; public class MainActivity @@ -27,6 +32,7 @@ class MainActivity private RendererRecyclerViewAdapter mRecyclerViewAdapter; private RecyclerView mRecyclerView; private GridLayoutManager mLayoutManager; + private SwipeRefreshLayout mSwipeToRefresh; @Override protected @@ -34,6 +40,16 @@ void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); + mSwipeToRefresh = (SwipeRefreshLayout) findViewById(R.id.refresh); + mSwipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() + { + @Override + public + void onRefresh() { + updateItems(); + } + }); + mRecyclerViewAdapter = new RendererRecyclerViewAdapter(); mRecyclerViewAdapter.registerRenderer(new HeaderViewRenderer(HeaderModel.TYPE, this)); mRecyclerViewAdapter.registerRenderer(new CategoryViewRenderer(CategoryModel.TYPE, this, mListener)); @@ -60,25 +76,49 @@ int getSpanSize(final int position) { mRecyclerView.setAdapter(mRecyclerViewAdapter); mRecyclerView.addItemDecoration(new EqualSpacesItemDecoration(20)); - mRecyclerViewAdapter.setItems(getItems()); - mRecyclerViewAdapter.notifyDataSetChanged(); + updateItems(); + } + + private + void updateItems() { +// mRecyclerViewAdapter.setItems(getItems()); +// mRecyclerViewAdapter.notifyDataSetChanged(); + + mRecyclerViewAdapter.setItems(getItems(), mDiffCallback); + mSwipeToRefresh.setRefreshing(false); } @NonNull private - ArrayList getItems() { - final ArrayList items = new ArrayList<>(); - items.add(new HeaderModel("header")); - for (int i = 0; i < 5; i++) { - items.add(new CategoryModel("some category #" + (i + 1))); - for (int j = 0; j < 12; j++) { - items.add(new ContentModel("content " + (j + 1))); + ArrayList getItems() { + final ArrayList items = new ArrayList<>(); + final int headerID = 1; + items.add(new HeaderModel(headerID, "header")); + + final int categoryCount = random(3, 9); + for (int i = 0; i < categoryCount; i++) { + final int categoryID = i * 10; + items.add(new CategoryModel(categoryID, "some category #" + (i + 1))); + + final ArrayList content = new ArrayList<>(); + final int contentCount = random(1, 9); + for (int j = 0; j < contentCount; j++) { + final int contentID = i * 10 + j; + content.add(new ContentModel(contentID, "content " + (j + 1))); } + Collections.shuffle(content); + items.addAll(content); } return items; } + private + int random(final int min, final int max) { + final Random random = new Random(); + return random.nextInt(max - min + 1) + min; + } + @NonNull private final ContentViewRenderer.Listener mListener = new ContentViewRenderer.Listener() { @@ -94,4 +134,52 @@ void onContentItemClicked(@NonNull final ContentModel model) { Toast.makeText(MainActivity.this, model.getName(), Toast.LENGTH_SHORT).show(); } }; + + @NonNull + private final RendererRecyclerViewAdapter.DiffCallback mDiffCallback = new RendererRecyclerViewAdapter + .DiffCallback() + { + + private final ArrayList mOldItems = new ArrayList<>(); + private final ArrayList mNewItems = new ArrayList<>(); + + @Override + public + void setItems(@NonNull final List oldItems, @NonNull final List newItems) { + mOldItems.clear(); + mOldItems.addAll(oldItems); + + mNewItems.clear(); + mNewItems.addAll(newItems); + } + + @Override + public + int getOldListSize() { + return mOldItems.size(); + } + + @Override + public + int getNewListSize() { + return mNewItems.size(); + } + + @Override + public + boolean areItemsTheSame(final int oldItemPosition, final int newItemPosition) { + final BaseItemModel oldItem = mOldItems.get(oldItemPosition); + final BaseItemModel newItem = mNewItems.get(newItemPosition); + return oldItem.getID() == newItem.getID(); + } + + @Override + public + boolean areContentsTheSame(final int oldItemPosition, final int newItemPosition) { + final ItemModel oldItem = mOldItems.get(oldItemPosition); + final ItemModel newItem = mNewItems.get(newItemPosition); + return oldItem.equals(newItem); + } + }; + } diff --git a/example/src/main/java/com/github/vivchar/immutableadapter/items/BaseItemModel.java b/example/src/main/java/com/github/vivchar/immutableadapter/items/BaseItemModel.java new file mode 100644 index 0000000..7eb2bea --- /dev/null +++ b/example/src/main/java/com/github/vivchar/immutableadapter/items/BaseItemModel.java @@ -0,0 +1,12 @@ +package com.github.vivchar.immutableadapter.items; + +import com.github.vivchar.rendererrecyclerviewadapter.ItemModel; + +/** + * Created by Vivchar Vitaly on 3/20/17. + */ +public interface BaseItemModel + extends ItemModel +{ + int getID(); +} diff --git a/example/src/main/java/com/github/vivchar/immutableadapter/items/category/CategoryModel.java b/example/src/main/java/com/github/vivchar/immutableadapter/items/category/CategoryModel.java index 05e410d..defcebf 100644 --- a/example/src/main/java/com/github/vivchar/immutableadapter/items/category/CategoryModel.java +++ b/example/src/main/java/com/github/vivchar/immutableadapter/items/category/CategoryModel.java @@ -2,25 +2,33 @@ import android.support.annotation.NonNull; -import com.github.vivchar.rendererrecyclerviewadapter.ItemModel; +import com.github.vivchar.immutableadapter.items.BaseItemModel; /** * Created by Vivchar Vitaly on 1/10/17. */ public class CategoryModel - implements ItemModel + implements BaseItemModel { public static final int TYPE = 0; + private final int mID; @NonNull private final String mTitle; public - CategoryModel(@NonNull final String title) { + CategoryModel(final int ID, @NonNull final String title) { + mID = ID; mTitle = title; } + @Override + public + int getID() { + return mID; + } + @Override public int getType() { @@ -32,4 +40,31 @@ int getType() { String getName() { return mTitle; } + + @Override + public + boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final CategoryModel that = (CategoryModel) o; + + if (mID != that.mID) { + return false; + } + return mTitle.equals(that.mTitle); + + } + + @Override + public + int hashCode() { + int result = mID; + result = 31 * result + mTitle.hashCode(); + return result; + } } diff --git a/example/src/main/java/com/github/vivchar/immutableadapter/items/content/ContentModel.java b/example/src/main/java/com/github/vivchar/immutableadapter/items/content/ContentModel.java index ff2afe8..634f7a7 100644 --- a/example/src/main/java/com/github/vivchar/immutableadapter/items/content/ContentModel.java +++ b/example/src/main/java/com/github/vivchar/immutableadapter/items/content/ContentModel.java @@ -2,24 +2,33 @@ import android.support.annotation.NonNull; -import com.github.vivchar.rendererrecyclerviewadapter.ItemModel; +import com.github.vivchar.immutableadapter.items.BaseItemModel; /** * Created by Vivchar Vitaly on 1/10/17. */ public -class ContentModel implements ItemModel +class ContentModel + implements BaseItemModel { public static final int TYPE = 1; + private final int mID; @NonNull private final String mName; public - ContentModel(@NonNull final String name) { + ContentModel(final int ID, @NonNull final String name) { + mID = ID; mName = name; } + @Override + public + int getID() { + return mID; + } + @Override public int getType() { @@ -31,4 +40,31 @@ int getType() { String getName() { return mName; } + + @Override + public + boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final ContentModel that = (ContentModel) o; + + if (mID != that.mID) { + return false; + } + return mName.equals(that.mName); + + } + + @Override + public + int hashCode() { + int result = mID; + result = 31 * result + mName.hashCode(); + return result; + } } diff --git a/example/src/main/java/com/github/vivchar/immutableadapter/items/header/HeaderModel.java b/example/src/main/java/com/github/vivchar/immutableadapter/items/header/HeaderModel.java index cac764d..67a4279 100644 --- a/example/src/main/java/com/github/vivchar/immutableadapter/items/header/HeaderModel.java +++ b/example/src/main/java/com/github/vivchar/immutableadapter/items/header/HeaderModel.java @@ -2,25 +2,33 @@ import android.support.annotation.NonNull; -import com.github.vivchar.rendererrecyclerviewadapter.ItemModel; +import com.github.vivchar.immutableadapter.items.BaseItemModel; /** * Created by Vivchar Vitaly on 3/6/17. */ public class HeaderModel - implements ItemModel + implements BaseItemModel { public static final int TYPE = 2; + private final int mID; @NonNull private final String mName; public - HeaderModel(@NonNull final String name) { + HeaderModel(final int ID, @NonNull final String name) { + mID = ID; mName = name; } + @Override + public + int getID() { + return mID; + } + @Override public int getType() { @@ -32,4 +40,31 @@ int getType() { String getName() { return mName; } + + @Override + public + boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final HeaderModel that = (HeaderModel) o; + + if (mID != that.mID) { + return false; + } + return mName.equals(that.mName); + + } + + @Override + public + int hashCode() { + int result = mID; + result = 31 * result + mName.hashCode(); + return result; + } } diff --git a/example/src/main/res/layout/main.xml b/example/src/main/res/layout/main.xml index 2ff1f43..c0b045e 100644 --- a/example/src/main/res/layout/main.xml +++ b/example/src/main/res/layout/main.xml @@ -1,16 +1,26 @@ - - - + > + + + + + + diff --git a/rendererrecyclerviewadapter/build.gradle b/rendererrecyclerviewadapter/build.gradle index 4d9800f..fbd662e 100644 --- a/rendererrecyclerviewadapter/build.gradle +++ b/rendererrecyclerviewadapter/build.gradle @@ -7,7 +7,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 25 - versionCode 5 + versionCode 9 versionName "1.0" } buildTypes { @@ -19,6 +19,6 @@ android { } dependencies { - compile 'com.android.support:support-annotations:25.1.1' - compile 'com.android.support:recyclerview-v7:25.1.1' + compile 'com.android.support:support-annotations:25.3.0' + compile 'com.android.support:recyclerview-v7:25.3.0' } diff --git a/rendererrecyclerviewadapter/src/main/java/com/github/vivchar/rendererrecyclerviewadapter/RendererRecyclerViewAdapter.java b/rendererrecyclerviewadapter/src/main/java/com/github/vivchar/rendererrecyclerviewadapter/RendererRecyclerViewAdapter.java index 1c46be4..4e309f0 100644 --- a/rendererrecyclerviewadapter/src/main/java/com/github/vivchar/rendererrecyclerviewadapter/RendererRecyclerViewAdapter.java +++ b/rendererrecyclerviewadapter/src/main/java/com/github/vivchar/rendererrecyclerviewadapter/RendererRecyclerViewAdapter.java @@ -1,6 +1,7 @@ package com.github.vivchar.rendererrecyclerviewadapter; import android.support.annotation.NonNull; +import android.support.v7.util.DiffUtil; import android.support.v7.widget.RecyclerView; import android.util.SparseArray; import android.view.ViewGroup; @@ -84,4 +85,29 @@ void setItems(@NonNull final List items) { mItems.clear(); mItems.addAll(items); } + + /** + * @param items - your new items + * @param diffCallback - callback class used by DiffUtil while calculating the diff between two lists. + */ + @SuppressWarnings("unchecked") + public + void setItems(@NonNull final List items, @NonNull final DiffCallback diffCallback) { + diffCallback.setItems(mItems, items); + + final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback); + + mItems.clear(); + mItems.addAll(items); + + diffResult.dispatchUpdatesTo(this); + } + + public abstract static + class DiffCallback + extends DiffUtil.Callback + { + public abstract + void setItems(@NonNull final List oldItems, @NonNull final List newItems); + } } \ No newline at end of file