epoxy icon indicating copy to clipboard operation
epoxy copied to clipboard

Viewstate is not saved while using AsyncEpoxyController

Open adiazarya100 opened this issue 3 years ago • 3 comments

We have a vertical Epxoy recycler view with shouldSaveViewState enabled. When the user clicks on an item (EpoxyModelWithHolder) we react to the click by changing the layout's views. As an example, if the EpoxyModelWithHolder has 3 cards (views) inside and the user clicks on one of them, after the user clicks the view color will change from white to red.

When the user scrolls down, to bound new elements, we have noticed that the Epoxy recycler view rebounds the view with the previous views for example view holder number 1 and view holder number 5 will have the same "red card" selected. As far as I understand from the docs the Epoxy recycler should keep the views state after the user modify the layout/view.

"Saving view state is useful for cases where the view is modified by the user, such as checkboxes, edit texts, expansion/collapse, etc. These can be considered transient state that the model doesn't need to know about." Link to docs

Each model has a unique id. We are using epoxy:4.6.2

class SorbetWallEpoxyController(val listItems: List<SorbetComponent>) : SorbetAsyncEpoxyController() {

  override fun buildModels() {
    listItems.forEachIndexed { index, it ->
      buildComponents(index, it)
    }
  }

  fun buildComponents(index: Int, item: SorbetComponent) {
    when (item.type) {
      TWO_CARDS_COMPONENT -> addSorbetBasicQuery(index, item, R.layout.two_cards)
      THREE_CARDS_COMPONENT -> addSorbetBasicQuery(index, item, R.layout.three_cards)
    }
  }

  private fun addSorbetBasicQuery(index: Int, sorbetWallQueryItem: SorbetComponent, layout: Int) {
    basicSorbetQuery {
      id(sorbetWallQueryItem.id)
      layout(layout)
      sorbetWallItem(sorbetWallQueryItem)
    }
  }
}

Any help will be welcome :)
Thanks.

adiazarya100 avatar Dec 13 '21 15:12 adiazarya100

When shouldSaveViewState is enabled Epoxy simply saves the view's state as a bundle, and restores it to the view with the same id when it is rebound. It sounds likely that your view's saving/restoring state logic or binding logic isn't quite right

elihart avatar Dec 15 '21 18:12 elihart

"It sounds likely that your view's saving/restoring state logic or binding logic isn't quite right"

Let me elaborate about our saving/restoring state logic and binding logic: "saving" => shouldSaveViewState is enabled "restoring" => nothing because the shouldSaveViewState is enabled. Is there something else we need to do?

"binding logic" => We bind the view according to the @EpoxyAttribute we have. Let's say the @EpoxyAttribute is a class:

class Card {
  var selectedCard: Int = -1
}

After the user click on a card we change the selectedCard to the index of the card (we have a maximum of 3 cards so the value can be: 1, 2, or 3) The bind function looks for the selectedCard value and sets the view of the selected Card to be red.

is our binding logic correct according to the example above?

adiazarya100 avatar Dec 25 '21 14:12 adiazarya100

it sounds like you're confusing view saved state and bound data. view saved state is not at all related to bound data, and is separate and entirely internal to the view. the view implements it like in https://medium.com/super-declarative/android-how-to-save-state-in-a-custom-view-30e5792c584b

elihart avatar Jan 12 '22 06:01 elihart