Provider: version 4.1.0 use select widget found leaks

Created on 8 May 2020  路  4Comments  路  Source: rrousselGit/provider

I found selectorDependency.selectors will add aspect many times and never clean.
inherited_provider.dart

@override
  void updateDependencies(Element dependent, Object aspect) {
    final dependencies = getDependencies(dependent);
    // once subscribed to everything once, it always stays subscribed to everything
    if (dependencies != null && dependencies is! _Dependency<T>) {
      return;
    }
    if (aspect is _SelectorAspect<T>) {
      final selectorDependency =
          (dependencies ?? _Dependency<T>()) as _Dependency<T>;
      if (selectorDependency.shouldClearSelectors) {
        selectorDependency.shouldClearSelectors = false;
        selectorDependency.selectors.clear();
      }
      if (selectorDependency.shouldClearMutationScheduled == false) {
        selectorDependency.shouldClearMutationScheduled = true;
        SchedulerBinding.instance.addPostFrameCallback((_) {
          selectorDependency.shouldClearSelectors = true;
        });
      }
      print('updateDependencies ${selectorDependency.selectors.length}');
      selectorDependency.selectors.add(aspect);<--------------aspect leak
      setDependencies(dependent, selectorDependency);
    } else {
      // subscribes to everything
      setDependencies(dependent, const Object());
    }
  }

Most helpful comment

Oh interesting. It sounds like the internal == comparison is performed on the wrong object

I'll investigate

All 4 comments

I also found this problem.

Could you give a way to reproduce the issue?

Could you give a way to reproduce the issue?

ok this is my test code.you can run it and click the items star, when click one item, it's ok, but when you click more, it will rebuild other item. see log _buildGoodsItem.

class ThirdPage2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Third Page')),
      body: ChangeNotifierProvider(
        create: (_) => GoodsList(),
        child: Builder(builder: _buildGoodsListView),

      ),
    );
  }

  Widget _buildGoodsListView(BuildContext context) {
    print('_buildGoodsListView');
    final model = Provider.of<GoodsList>(context,listen: false);
    return ListView.builder(
      itemCount: model.total,
      itemBuilder: (context1, index)=>Builder(builder: (context2)=>_buildGoodsItem(context2,index)),
    );
  }

  Widget _buildGoodsItem(BuildContext context, int index) {
    print('_buildGoodsItem $index');
    final name =
        context.select((GoodsList model) => model.goodList[index].goodsName);
    final liked =
        context.select((GoodsList model) => model.goodList[index].isLiked);
//    final model = context.select((GoodsList model) => model);
    return ListTile(
      title: Text(name),
      trailing: GestureDetector(
        onTap: () => context.read<GoodsList>().like(index),
        child: Icon(liked? Icons.star : Icons.star_border),
      ),
    );
  }
}

class GoodsList with ChangeNotifier{
  List<Goods> _goodList = List.generate(20, (index) => Goods(false,'Good No. $index'));
  List<Goods> get goodList=>_goodList;
  int get total=>_goodList.length;

  like(int index){
    var goods = _goodList[index];
    _goodList[index]._isLiked = !goods.isLiked;
    print('like index = $index');
    notifyListeners();
  }

}
class Goods{
   Goods(this._isLiked,this._goodsName);
   String _goodsName;
  String get goodsName =>_goodsName;
   bool _isLiked;
  bool get isLiked => _isLiked;

}

Oh interesting. It sounds like the internal == comparison is performed on the wrong object

I'll investigate

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wemped picture wemped  路  5Comments

guopeng1994 picture guopeng1994  路  4Comments

rrousselGit picture rrousselGit  路  3Comments

dikir picture dikir  路  5Comments

Alfie-AD picture Alfie-AD  路  4Comments