likes
comments
collection
share

Flutter Provider Selector数据更新问题优化

作者站长头像
站长
· 阅读数 20

在使用Selector的时候,在修改所选对象里面的某个参数之后调用notifyListeners(),界面并不会更新,再比如选择的是个数组,对数组进行操作之后,调用notifyListeners()也是不会更新,造成这个问题的主要原因是由于对象内存地址并没有改变导致的,当内存地址没有改变,就不会更新。

我们为了解决这个问题,一般是重新创建一个对象, 然后把原来的值重新赋值到新的对象上,比如数组:

List<String> newList=[];
newList.addAll(list);
newList.add("test");
list=newList;
notifyListeners(); 

当这个数组是个对象数组的时候,我们需要修改数组里面的对象里面的某个参数的时候,不仅数组需要重建,里面的对象也需要重建,比如:

List<User> newList = [];
newList.addAll(list);
newList[index] = User()
  ..name = "test1"
  ..age=list[index].age
  ..gender=list[index].gender;
list = newList;
notifyListeners();

这虽然能够解决问题,但是非常麻烦,并且效率不高。

优化

查看Selector的属性可以发现有个shouldRebuild这个属性,里面有两个值,一个是收到更新通知之后新的数据,一个还是缓存的数据,通过判断这两个值来决定是否刷新,默认preview!=next就刷新,我们可以通过这个属性来做一些处理进行优化。

我们只需要加上version,通过它来判断数据是否有更新便可以了

 bool shouldRebuild() {
    bool isUpdate = _version != _lastVersion;
    if (isUpdate) {
      _lastVersion = _version;
    }
    return isUpdate;
  }

我们对其进行一下封装,首先定义一个类来进行承载数据,传入的泛型就会Selector中用到的数据类型

class SelectorPlusData<T> {
  T? _value;
  int _version = 0;
  int _lastVersion = -1;

  T? get value => _value;

  SelectorPlusData({Key? key, T? value}) {
    _value = value;
  }

  set value(T? value) {
    _version++;
    _value = value;
  }

  bool shouldRebuild() {
    bool isUpdate = _version != _lastVersion;
    if (isUpdate) {
      _lastVersion = _version;
    }
    return isUpdate;
  }
}

接着对Selector也进行一下处理

class SelectorPlus<A, T> extends Selector<A, SelectorPlusData<T?>> {
  SelectorPlus({
    Key? key,
    required ValueWidgetBuilder<T?> builder,
    required SelectorPlusData<T?> selector,
    ShouldRebuild<SelectorPlusData>? shouldRebuild,
    Widget? child,
  }) : super(
    key: key,
    builder: (context, value, child) =>
        builder(context, value.value, child),
    selector: (context, value) => selector,
    shouldRebuild: (previous, next) => next.shouldRebuild(),
    child: child,
  );
}

使用

比如我们需要监听的对象是UserModel

SelectorPlus<UserController, UserModel>(
  selector: controller.data,
  builder: (context, value, child) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            "name: ${value?.name}",
          ),
          Text(
            "email: ${value?.email}",
          ),
        ],
      ),
    );
  },
)

修改数据,然后刷新UI

data.value?.name = 'Flutter';
data.update();
notifyListeners();

或者

data.value = UserModel(name: "Flutter", email: "123@xx.com");
notifyListeners();

当然,对数组类数据也进一步做了处理,具体使用如下:

SelectorListPlus<UserController, UserModel>(
  selector: controller.list,
  builder: (context, value, child) {
    return ListView.builder(
      itemCount: value.length,
      itemBuilder: (context, index) {
        final item = value[index];
        return ListTile(
          title: Text(item.name),
          subtitle: Text(item.email),
        );
      },
    );
  },
)

修改数据更新UI

list.value[index].name = 'Flutter';
list.update();
notifyListeners();

或者

list.value= [UserModel(name: "Flutter", email: "123@xxx.com")];
notifyListeners();

增加

list.add(UserModel(name: "Flutter", email: "123@xx.com"));
notifyListeners();

删除

list.remove(index);
notifyListeners();
最后

GitHub地址:selector_plus