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

点击取关后

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BLoC(Business Logic Component)是一种状态管理模式,它将业务逻辑从UI层中分离出来,并提供了一种统一的方式来管理状态。在Flutter中,BLoC通常使用Stream和Sink来实现,可以通过监听Stream来获取状态更新,并通过Sink来发送新的状态。 在BLoC中,刷新UI的方法通常是通过StreamBuilder来实现的。StreamBuilder是一个Flutter内置的Widget,用于监听Stream并根据新的数据刷新UI。当Stream中有新数据时,StreamBuilder会自动调用builder回调函数,并将新的数据传递给该函数,从而实现UI刷新。 以下是一个简单的BLoC示例,演示了如何使用StreamController和StreamBuilder来实现状态管理和UI刷新: ```dart import 'dart:async'; import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class CounterBloc { int _counter = 0; final _counterController = StreamController<int>(); Stream<int> get counterStream => _counterController.stream; void incrementCounter() { _counter++; _counterController.sink.add(_counter); } void dispose() { _counterController.close(); } } final counterBloc = CounterBloc(); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter BLoC Demo', home: MyHomePage(), ); } } class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter BLoC Demo"), ), body: Center( child: StreamBuilder<int>( stream: counterBloc.counterStream, builder: (context, snapshot) { if (!snapshot.hasData) { return CircularProgressIndicator(); } return Text( 'Counter: ${snapshot.data}', style: TextStyle(fontSize: 24.0), ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () { counterBloc.incrementCounter(); }, child: Icon(Icons.add), ), ); } } ``` 在这个示例中,我们创建了一个CounterBloc类来管理计数器状态,它包含一个_counter变量和一个_counterController StreamController对象。当调用incrementCounter方法时,_counter变量会自增,并通过_counterController的sink属性将新值发送到Stream中。 在MyHomePage中,我们使用StreamBuilder来监听CounterBloc的counterStream,并根据新的数据刷新UI。当Stream中没有数据时,我们显示一个CircularProgressIndicator,表示数据还未准备好。当有新的数据时,我们使用Text Widget来显示计数器的值。 当用户点击FloatingActionButton时,我们调用CounterBloc的incrementCounter方法来增加计数器的值,并通过StreamBuilder自动更新UI。 总之,BLoC模式可以使得Flutter应用程序的状态管理更加清晰和可维护,而StreamBuilder则是BLoC模式中刷新UI的关键。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值