Flutter Key的原理和使用(三) LocalKey的三種型別

__white發表於2021-08-29

這是我參與8月更文挑戰的29天,活動詳情檢視:8月更文挑戰

Flutter Key的原理和使用 (一) 沒有Key會發生什麼 (juejin.cn)

Flutter Key的原理和使用 (二) Widget 和 Element 的對應關係 (juejin.cn)

我們在上一章說到,同一級中相同型別的Widget不給它傳Key的話,Flutter有時候就會出現分不清它們之間的對應關係,尤其是Widget之間的順序發生改變的時候. 此時,我們就需要傳個key給它.

Key的種類

Key有兩個子類:

  • LocalKey 區域性鍵,在同一級中要唯一,可以理解為同級唯一性
  • GlobalKey 全域性鍵 , 在整個App中必須是唯一的.

從效能上來講,如果不需要用到GlobalKey的話,儘量不用,LocalKey因為只對比同一級別,因此會快很多.上一章也說過,在父級或者子級是不會需考慮的. 如果違背了上述的唯一性原則,執行時會報錯,提示你Key沒有隻出現一次.

LocalKey

而LocalKey又有3個子類

  • ValueKey
  • ObjectKey
  • UniqueKey

其實當你的Widget全都是StatelessWidget的時候,不需要用到Key,只有當使用Statefuldiget的時候才有可能用到key.

ValueKey

const ValueKey(this.value)

final T value;

@override
bool operator ==(Object other) {
  if (other.runtimeType != runtimeType)
    return false;
  return other is ValueKey<T>
      && other.value == value;
}
複製程式碼

它的構造方法很簡單,有一個value,型別是T,也就是隨便你想傳什麼都可以.當然因為唯一性原則,同級中Valukey的value是不能相同的.這個可以看它的operator方法.

ObjectKey

const ObjectKey(this.value);

final Object? value;

@override
bool operator ==(Object other) {
  if (other.runtimeType != runtimeType)
    return false;
  return other is ObjectKey
      && identical(other.value, value);
}
複製程式碼

ObjectKey跟ValueKey大同小異,我們主要看一下區別,value的型別從T變成了Object,operator方法也不一樣. identical對比是否是相等或者說相同的時候,它其實屬於對比引用或者說指標是否相等,類似於Java中對比記憶體地址.

我們建立一個稍微複雜一點的類看一下二者實際的區別:

class People{
  final String name;
  final int age;

  People(this.name, this.age);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is People && runtimeType == other.runtimeType && name == other.name && age == other.age;

  @override
  int get hashCode => name.hashCode ^ age.hashCode;
}
複製程式碼

主要看一下operator方法,當年齡相等並且姓名相等時,就判斷是相等的. 此時如果程式碼是這樣的話:

Box(Colors.red, key: ValueKey(People('a', 18))),
Box(Colors.red, key: ValueKey(People('a', 18))),
複製程式碼

執行之後,

image.png

啊,果不其然,報錯了. 然後我們換成ObjectKey試試:

11123123.gif

這就是因為People('a', 18)是new出來的新物件(在dart中,new關鍵字是可以被省略的),flutter判斷二者不是同一個物件,因為對應的ObjectKey也不相等. 這就是ObjectKey跟ValueKey的主要區別.

UniqueKey

class UniqueKey extends LocalKey {
  UniqueKey();

  @override
  String toString() => '[#${shortHash(this)}]';
}
複製程式碼

顧名思義,UniqueKey是一個獨一無二的Key,也就是說它只和自己相等.因此UniqueKey()UniqueKey()是不相等的.

aas.gif 可以看到,換成UniqueKey之後,再進行hot reload,發現狀態丟失了,因為Key變了, 新的UniqueKey和舊的是不相等的.所以state就沒有辦法保留下來.

那麼問題來了, 這玩意到底有啥用?

其實,丟失狀態就是它的一種用法,一般在動畫效果中會用到. 另外就是它不需要value,當你不想傳個value的時候,像我經常有起名頭疼的毛病,需要key的時候,這個value該傳什麼值, 我得想一會,可能還想不好,索性不傳了,此時可以使用UniqueKey.

那就又有個問題,它每次都會丟掉狀態啊,不是我們希望的,怎麼辦?

把UniqueKey定義到build的外部,比如

final keyRed = UniqueKey();
final keyBlue = UniqueKey();
複製程式碼

因為是一開始就new出來的兩個Key,所以在使用的時候,keyRed是沒有改變的,也就達到了我們的目的.

GlobalKey

ok,接下來說到GlobalKey , 因為標題的原因啊,我們下一章再講它.

相關文章