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

點擊取關後

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章