gpt4 book ai didi

android - 模型建成后,环氧树脂会更新模型中的环氧树脂属性,从而导致崩溃

转载 作者:行者123 更新时间:2023-12-03 08:15:50 29 4
gpt4 key购买 nike

应用程序崩溃,正在执行 CustomActivityOnCrash 的 UncaughtExceptionHandler

com.airbnb.epoxy.ImmutableModelException: The model was changed between being added to the controller and being bound

Controller 类

class SortFilterController @Inject constructor(
private val schedulersFacade: SchedulersFacade,
private val generateMapOfCategoryFilters: GenerateMapOfCategoryFilters
) : EpoxyController() {

private val tapCountryRelay: PublishRelay<TopsProductFilter> = PublishRelay.create()

var sortFilterViewState: SortFilterViewState = SortFilterViewState()
set(value) {
field = value
requestModelBuild()
}

var sortFilterType: SortFilterType = SortFilterType.ALL
set(value) {
field = value
requestModelBuild()
}

override fun buildModels() {
sortFilterViewState.let { sortFilterViewState ->
sortFilterViewState.filterTypes?.forEach { topsProductFilter ->
when (SortFilterType.getId(topsProductFilter.attributeCode)) {
SortFilterType.COUNTRY -> {
CountryItemModel_()
.id(UUID.randomUUID().toString())
.tapCountryChipRelay(tapCountryRelay)
.countryFilter(topsProductFilter)
.listOfPreSelectedCountryFilters(sortFilterViewState.listOfCurrentlySelectedCountryItems ?: emptyList())
.addTo(this)
}
}
}
}
}

val bindTapCountryRelay: Observable<TopsProductFilter> = tapCountryRelay.hide()
}

//模型类

@EpoxyModelClass(layout = R.layout.list_item_country_item)
abstract class CountryItemModel : EpoxyBaseModel() {

@EpoxyAttribute
lateinit var tapCountryChipRelay: PublishRelay<TopsProductFilter>

@EpoxyAttribute
lateinit var countryFilter: TopsProductFilter

@EpoxyAttribute
lateinit var listOfPreSelectedCountryFilters: MutableList<TopsProductFilterItem>

override fun bind(holder: EpoxyBaseViewHolder) {
with(holder.itemView) {
// snippet here
}
}
}

在 DialogFragment oncreate 中,我设置了 EpoxyRecyclerView。

 epoxyRecyclerView.setController(sortFilterController)
epoxyRecyclerView.layoutManager = LinearLayoutManager(requireContext(), RecyclerView.VERTICAL, false)

并调用 Controller 上的 setter 并请求模型构建

sortFilterController.sortFilterViewState = sortFilterViewState
sortFilterController.sortFilterType = SortFilterType.ALL

但是,问题是我想用一些新数据更改模型中显示的数据。因此,当用户点击一个国家/地区时,我想再次设置 setter 。

  private fun onTapClearAll() {
// sortFilterViewState has some new data so I want to set it again for display.

// This calling these resulted in a crash as the models epoxy attributes have changed with this new data
sortFilterController.sortFilterViewState = sortFilterViewState
sortFilterController.sortFilterType = SortFilterType.ALL
}

// Then I tried to do the same with a interceptor but again the app will crash.
private fun onTapClearAll() {
sortFilterController.addInterceptor(object : EpoxyController.Interceptor {
override fun intercept(models: MutableList<EpoxyModel<*>>) {
val countryModel = models[0] as CountryItemModel_

countryModel.listOfPreSelectedCountryFilters(sortFilterViewState.listOfCurrentlySelectedCountryItems)
}
})
sortFilterController.requestModelBuild()
}

最佳答案

问题

我不是Epoxy专家,但是Epoxy模型在添加到 Controller 后要求不能修改。这意味着不仅要修改它们的直接属性,还要修改这些属性的深层内容。

在您的 buildModels() 中,您总是创建全新的 CountryItemModel_ 对象,这很好,但是您用存储在其他地方的对象(主要是在 中)填充它们sortFilterViewState 和哪些是可变的。这在您提供的源代码中不可见,但我猜您随后修改了 sortFilterViewState 的内容,因此您实际上也修改了已经创建的模型。

例如,如果您在创建模型后修改 listOfCurrentlySelectedCountryItems,则现有模型中的 listOfPreSelectedCountryFilters 也会受到影响,因为它们实际上引用完全相同列表。 Epoxy 禁止修改 listOfPreSelectedCountryFilters,因为它是模型的一部分。

技术细节

Epoxy 使用 hashCode()equals() 来检测模型中的更改。大多数类通过委托(delegate)其属性的 hashCode()/equals() 来实现这些方法,因此可以深入检测更改。例如,如果我们有一些对象的列表,并且我们只修改其中一个项目中的单个属性,则该项目的 hashCode() 将发生变化,而该项目的 hashCode() 将发生变化。整个列表也会发生变化。同样,如果我们添加新项目、删除某些项目或重新排序项目 - 列表的 hashCode() 也会发生变化。如果此类列表是 Epoxy 模型的一部分,这将被检测为模型中的更改,并将导致运行时错误。

这在 Epoxy wiki here 中有详细描述。和 here .

解决方案

此问题的正确解决方案是在将模型添加到 Controller 后不要对其进行修改。使模型深度不可变可能会有所帮助,例如确保 TopsProductFilterTopsProductFilterItem 的所有属性都是 val,而不是 var 并且如果其中一些属性保存对象,那么也使这些对象不可变。如果某个对象不能是不可变的,则在提供给模型时创建一个副本。例如,不要直接向模型提供 listOfCurrentlySelectedCountryItems,而是提供创建副本的 listOfCurrentlySelectedCountryItems.toMutableList()。请注意,这是一个浅拷贝,因此如果 TopsProductFilterItem 对象是可变的,那么您还需要创建所有项目的副本。

这个PublishRelay特别可疑。环氧树脂模型用于保存相对简单的数据,而中继的作用远不止于此。甚至很难具体说明它已经改变或没有改变意味着什么。我猜想当用 Epoxy 进行比较时可能会造成困惑。为什么模型中需要这个?

还有更简单的“解决方案”。您可以通过将 validateEpoxyModelUsage 设置为 false 来禁用模型验证。 Configuration 中对此进行了描述。 。我想我不必添加这是非常不鼓励的。

关于android - 模型建成后,环氧树脂会更新模型中的环氧树脂属性,从而导致崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69478587/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com