question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

com.airbnb.epoxy.ImmutableModelException: The model was changed between being bound and when models were rebuilt

See original GitHub issue

Hello,

I’m working on a project and I having some trouble with rebuilding the Views through EpoxyController.

Everytime I change some of the data inside the View and call the TypedEpoxyController SetData my app crashes with the error:

com.airbnb.epoxy.ImmutableModelException: The model was changed between being bound and when models were rebuilt Position: 0 Model: // Model Data Here

Epoxy attribute fields on a model cannot be changed once the model is added to a controller. Check that these fields are not updated, or that the assigned objects are not mutated, outside of the buildModels method. The only exception is if the change is made inside an Interceptor callback. Consider using an interceptor if you need to change a model after it is added to the controller and before it is set on the adapter. If the model is already set on the adapter then you must call requestModelBuild instead to recreate all models.

Code:

class CheckoutFragment : ContainerFragment(), CheckoutController.Listener
{

  override val TAG: String = CheckoutFragment::class.java.name
  lateinit var viewModel: CheckoutViewModel
  private lateinit var checkoutProducts: MutableList<Product>
  private lateinit var controller: CheckoutController
  override val toolbarLayout: InteraToolbar?
    get() = toolbar

  companion object {
    fun newInstance(backNavigationEnabled: Boolean = false) = CheckoutFragment().apply {
      arguments = bundleOf(BACK_NAVIGATION_ENABLED to backNavigationEnabled)
    }
  }

  override fun layoutRes(): Int = R.layout.fragment_checkout

  override fun onViewCreated(view: View, savedInstanceState: Bundle?)
  {
    super.onViewCreated(view, savedInstanceState)
    checkoutProducts = mutableListOf()
    initViewModel()
    initRecyclerView()
  }

  private fun initViewModel()
  {
      viewModel= ViewModelProviders.of(this).get(CheckoutViewModel::class.java)
      viewModel.productLiveData.observe(this, Observer {
          checkoutProducts = it.toMutableList()
          updateController()
      })

      viewModel.applyService()
  }

  private fun initRecyclerView() {
    controller = CheckoutController(this)

    erv_product.itemAnimator?.changeDuration = 0
    erv_product.setController(controller)
    updateController()
  }

  private fun setDataAvailableLayout(isAvailable: Boolean) {
    group_calculate_shipping.showOrHide(isAvailable)
    group_content_layout.showOrHide(isAvailable) {
      cl_root.backgroundColorResource = R.color.white
      btn_proceed_with_order.textResource = R.string.proceed_with_order
      rg_payment_type.selectViewProgrammatically(R.id.rb_associated_total_text)
    }

    tv_no_content.showOrHide(!isAvailable) { //BREAKING HERE!!!
      cl_root.backgroundColorResource = R.color.color_f9f7eb
      btn_proceed_with_order.textResource = R.string.make_a_wish
    }

  }

  private fun updateController() {
    setDataAvailableLayout(checkoutProducts.isNotEmpty())
    controller.setData(checkoutProducts) // ERROR HAPPENS HERE AFTER CALLING IT AGAIN
  }

  override fun onRemoveClick(product: Product) {
    viewModel.remove(product)
    updateController()// CALL CRASH THE APP
  }

  override fun onFavoriteClick(product: Product) {
    viewModel.changeFavorite(product)
    product.isFavorite = !product.isFavorite
    updateController() // CALL CRASH THE APP
  }

  override fun onSelectionCountClick(product: Product) {
    val list = (1 .. 20).toList().map { it.toString() }
    selector("Select count", list) { dialog, position ->
      dialog.dismiss()
      val currentSelection = list[position]
       val quantity = currentSelection.toIntOrNull().orZero()
      viewModel.update(product, quantity)
      updateController()// CALL CRASH THE APP
    }
  }

I am really stuck at this. I tried a bunch of stuff but somehow I could not progress into making my EpoxyModels to update with the new product data.

Thanks in advance

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
elihartcommented, Sep 25, 2020

these errors should only be thrown when debug validations are enabled, so you can disabled that temporarily while you fix them.

These are errors that you do not want to ignore though, as they are real problems the can lead to your views not working properly

1reaction
MirzaShadmancommented, Apr 13, 2020

@elihart i am also facing the same issue. I also used the interceptors to update, but no luck. Same error i am getting. If needed i will paste my code. May i get help please ? Why it is so complicated to update models ?? It should be as easy as notifyDataSetChanged, isn’t it ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Epoxy updating the epoxy attributes in the models once they ...
Problem. I'm not the Epoxy expert, but Epoxy models are required to be not modified after they were added to the controller.
Read more >
com.airbnb.epoxy.EpoxyController.requestModelBuild java ...
Call this to request a model update. The controller will schedule a call to #buildModels() so that models can be rebuilt for the...
Read more >
Taming partial Epoxy models update | by Alla Dubovska
When a model's state changes, and the model is bound to a view on screen, Epoxy rebinds the view with only the properties...
Read more >
com.airbnb.epoxy.ImmutableModelException Maven / Gradle ...
package com.airbnb.epoxy; import android.support.annotation.NonNull; /** * Thrown if a model is changed after it is added to an {@link com.airbnb.epoxy.
Read more >
EpoxyController.java example - Javatips.net
package com.airbnb.epoxy; import android.os. ... Adapter} with the latest * models, which you can get via {@link #getAdapter()} to set on your RecyclerView....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found