Flutter Bloc更新状态后不刷新UI的一个解决办法

Flutter Bloc更新状态后不刷新UI的一个解决办法

Flutter 1.12.13+hotfix.8 • channel stable
使用Equatable 1.1.1创建Bloc

在用Bloc框架写一个项目时,发现在mapEventToStateyield一个state后发现UI并没有刷新,明明改变了关注状态。

究竟是怎么回事呢?

点击已关注没有反应

上原代码

class ...

TopicInfoEntity _entity;

...
            _entity.data.subscribeStatus = 0;
            yield GetTopicDetailState(_entity);

...

Github上搜寻结果发现,问题出在Equatable

abstract class TopicDetailState extends Equatable {
  const TopicDetailState();
}

class GetTopicDetailState extends TopicDetailState {
  final TopicInfoEntity infoEntity;

  GetTopicDetailState(this.infoEntity);

  @override
  List<Object> get props => [infoEntity];
}

我们知道,Bloc需要判断一个新state是否需要刷新原UI,需要判断二者state是否相等,如果相等则不刷新。

而我们使用的是需要判断二者是否相等,而Equatable接口便实现的是这个功能。它通过props传入的参数来判断二者是否相等。

那为什么两个有着不同参数的Entity会被判断相等呢?

我们来看Equatable的接口代码

@immutable
abstract class Equatable {
  List<Object> get props;
  bool get stringify => false;
  const Equatable();
  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Equatable &&
          runtimeType == other.runtimeType &&
          equals(props, other.props);
  @override
  int get hashCode => runtimeType.hashCode ^ mapPropsToHashCode(props);
  @override
  String toString() =>
      stringify ? mapPropsToString(runtimeType, props) : '$runtimeType';
}

注意!接口重载了==判断符,判断相同的条件满足以下2点之一即可

  • identical(this, other),即二者属于相同的Object
  • other(这里为传入的state)是实现Equatable的,且两个state的运行类型一样,且他们的props相同

经过分析,我们发现上述问题出在props上,于是我们调试进入equals方法。

props equals源码

果不其然,调试过程中,代码一路执行,走到了true

所以二者立刻的相等了,则不刷新UI

我们来看equals里面判断了什么:

判断List二者不相等的条件可以为:

  • 二者至少有一方是null
  • props的List长度不一致
  • 二者为Iterable的,或者为Map(如列表等),同时unit内部的元素也满足前面所述的equals元素(这个equals函数会针对不同数据类型做不同的判断,详情可查看源代码)

其他情况则直接为true


list中有我们的一个entity

  • 11行,两个list不相同,因为每创建一个state,一个空列表都会在state中实例化一次
  • 12行,二者都不为null
  • …以此类推

我们发现,判断两个entity是否相等,重点在与24行:

24行判断二者相等时,判断二者相等,因为:

== returns true if two objects are the same instance.

回到我们之前,原来!我们传入stateBloc中全局变量:相同的_entity,而我们只是改变了其中的一个值而已,两个object还是相等的,因为二者为引用的同一个实例关系


正确的写法

既然我们的Entity不支持Equatable类型…那我们可以另辟蹊径,新建一个元素,把值copy一遍

好在插件提供了以下方法可以达到copy的效果

...
            var nEntity = topicInfoEntityFromJson(
                TopicInfoEntity(), _entity.toJson());
            nEntity.data.subscribeStatus = 0;
            yield GetTopicDetailState(nEntity);
            _entity = nEntity;
...

改完后就能正常刷新啦~

调试我们也发现正常返回了false

点击取关后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值