From 12276bbc5138ebaaf22892f1ef3388a5eb2762f2 Mon Sep 17 00:00:00 2001 From: Eli Hart Date: Fri, 13 Oct 2017 18:24:41 -0700 Subject: [PATCH] Optimize model group partial binding --- .../com/airbnb/epoxy/EpoxyModelGroup.java | 63 ++++++++++++++----- .../sample/models/CarouselModelGroup.java | 8 ++- 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java b/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java index bf41f28191..a14295cf46 100644 --- a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java +++ b/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyModelGroup.java @@ -111,7 +111,7 @@ private EpoxyModelGroup(@LayoutRes int layoutRes, List> public void handlePostBind(Holder groupHolder, final int position) { iterateModels(groupHolder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { if (model instanceof GeneratedModel) { //noinspection unchecked ((GeneratedModel) model).handlePostBind(boundObject, position); @@ -124,7 +124,7 @@ public void onModel(EpoxyModel model, Object boundObject, View view) { public void handlePreBind(final EpoxyViewHolder holder, Holder groupHolder, final int position) { iterateModels(groupHolder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { if (model instanceof GeneratedModel) { //noinspection unchecked ((GeneratedModel) model).handlePreBind(holder, boundObject, position); @@ -138,7 +138,7 @@ public void onModel(EpoxyModel model, Object boundObject, View view) { public void bind(Holder holder) { iterateModels(holder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { setViewVisibility(model, view); //noinspection unchecked model.bind(boundObject); @@ -151,10 +151,39 @@ public void onModel(EpoxyModel model, Object boundObject, View view) { public void bind(Holder holder, final List payloads) { iterateModels(holder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { setViewVisibility(model, view); //noinspection unchecked - model.bind(boundObject, payloads); + model.bind(boundObject); + } + }); + } + + @Override + public void bind(Holder holder, EpoxyModel previouslyBoundModel) { + if (!(previouslyBoundModel instanceof EpoxyModelGroup)) { + bind(holder); + return; + } + + final EpoxyModelGroup previousGroup = (EpoxyModelGroup) previouslyBoundModel; + if (previousGroup.models.size() != models.size()) { + throw createInconsistentModelCountException(); + } + + iterateModels(holder, new IterateModelsCallback() { + @Override + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { + setViewVisibility(model, view); + + EpoxyModel previousModel = previousGroup.models.get(modelIndex); + if (previousModel.id() == model.id()) { + //noinspection unchecked + model.bind(boundObject, previousModel); + } else { + //noinspection unchecked + model.bind(boundObject); + } } }); } @@ -172,7 +201,7 @@ private static void setViewVisibility(EpoxyModel model, View view) { public void unbind(Holder holder) { iterateModels(holder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { //noinspection unchecked model.unbind(boundObject); } @@ -184,7 +213,7 @@ public void onModel(EpoxyModel model, Object boundObject, View view) { public void onViewAttachedToWindow(Holder holder) { iterateModels(holder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { //noinspection unchecked model.onViewAttachedToWindow(boundObject); } @@ -196,7 +225,7 @@ public void onModel(EpoxyModel model, Object boundObject, View view) { public void onViewDetachedFromWindow(Holder holder) { iterateModels(holder, new IterateModelsCallback() { @Override - public void onModel(EpoxyModel model, Object boundObject, View view) { + public void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex) { //noinspection unchecked model.onViewDetachedFromWindow(boundObject); } @@ -206,11 +235,7 @@ public void onModel(EpoxyModel model, Object boundObject, View view) { private void iterateModels(Holder holder, IterateModelsCallback callback) { int modelCount = models.size(); if (modelCount != holder.views.size()) { - throw new IllegalStateException( - "The number of models used in this group has changed. The model count must remain " - + "constant if the same layout resource is used. If you need to change which models" - + " are shown you can call EpoxyMode#hide() to have a model's view hidden, or use a" - + " different layout resource for the group."); + throw createInconsistentModelCountException(); } for (int i = 0; i < modelCount; i++) { @@ -219,12 +244,20 @@ private void iterateModels(Holder holder, IterateModelsCallback callback) { EpoxyHolder epoxyHolder = holder.holders.get(i); Object objectToBind = (model instanceof EpoxyModelWithHolder) ? epoxyHolder : view; - callback.onModel(model, objectToBind, view); + callback.onModel(model, objectToBind, view, i); } } + private RuntimeException createInconsistentModelCountException() { + return new IllegalStateException( + "The number of models used in this group has changed. The model count must remain " + + "constant if the same layout resource is used. If you need to change which models" + + " are shown you can call EpoxyMode#hide() to have a model's view hidden, or use a" + + " different layout resource for the group."); + } + private interface IterateModelsCallback { - void onModel(EpoxyModel model, Object boundObject, View view); + void onModel(EpoxyModel model, Object boundObject, View view, int modelIndex); } @Override diff --git a/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/models/CarouselModelGroup.java b/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/models/CarouselModelGroup.java index bd7b5e7973..e5fbeb28ed 100644 --- a/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/models/CarouselModelGroup.java +++ b/epoxy-sample/src/main/java/com/airbnb/epoxy/sample/models/CarouselModelGroup.java @@ -26,20 +26,24 @@ private static List> buildModels(CarouselData carousel, ArrayList> models = new ArrayList<>(); models.add(new ImageButtonModel_() + .id("add") .imageRes(R.drawable.ic_add_circle) .clickListener(v -> callbacks.onAddColorToCarouselClicked(carousel))); models.add(new ImageButtonModel_() + .id("delete") .imageRes(R.drawable.ic_delete) .clickListener(v -> callbacks.onClearCarouselClicked(carousel)) .show(colors.size() > 0)); models.add(new ImageButtonModel_() + .id("change") .imageRes(R.drawable.ic_change) .clickListener(v -> callbacks.onChangeCarouselColorsClicked(carousel)) .show(colors.size() > 0)); models.add(new ImageButtonModel_() + .id("shuffle") .imageRes(R.drawable.ic_shuffle) .clickListener(v -> callbacks.onShuffleCarouselColorsClicked(carousel)) .show(colors.size() > 1)); @@ -59,7 +63,9 @@ private static List> buildModels(CarouselData carousel, })); } - models.add(new GridCarouselModel_().models(colorModels)); + models.add(new GridCarouselModel_() + .id("carousel") + .models(colorModels)); return models; }