我目前正在阅读provider包的示例代码:
// ignore_for_file: public_member_api_docs
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => Counter()),
],
child: Consumer<Counter>(
builder: (context, counter, _) {
return MaterialApp(
supportedLocales: const [Locale('en')],
localizationsDelegates: [
DefaultMaterialLocalizations.delegate,
DefaultWidgetsLocalizations.delegate,
_ExampleLocalizationsDelegate(counter.count),
],
home: const MyHomePage(),
);
},
),
);
}
}
class ExampleLocalizations {
static ExampleLocalizations of(BuildContext context) =>
Localizations.of<ExampleLocalizations>(context, ExampleLocalizations);
const ExampleLocalizations(this._count);
final int _count;
String get title => 'Tapped $_count times';
}
class _ExampleLocalizationsDelegate
extends LocalizationsDelegate<ExampleLocalizations> {
const _ExampleLocalizationsDelegate(this.count);
final int count;
@override
bool isSupported(Locale locale) => locale.languageCode == 'en';
@override
Future<ExampleLocalizations> load(Locale locale) =>
SynchronousFuture(ExampleLocalizations(count));
@override
bool shouldReload(_ExampleLocalizationsDelegate old) => old.count != count;
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Title()),
body: const Center(child: CounterLabel()),
floatingActionButton: const IncrementCounterButton(),
);
}
}
class IncrementCounterButton extends StatelessWidget {
const IncrementCounterButton({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return FloatingActionButton(
onPressed: Provider.of<Counter>(context).increment,
tooltip: 'Increment',
child: const Icon(Icons.add),
);
}
}
class CounterLabel extends StatelessWidget {
const CounterLabel({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context);
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'${counter.count}',
style: Theme.of(context).textTheme.display1,
),
],
);
}
}
class Title extends StatelessWidget {
const Title({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(ExampleLocalizations.of(context).title);
}
}
字符串
一开始我对下面的代码感到困惑。它是一个MultiProvider,紧接着是一个Consumer,位于Widget树的顶部:
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_)=>Counter()),
],
child: Consumer<Counter>(
builder: (context, counter, _){
return MaterialApp(
home: const MyHomePage()
);
},
),
);
型
我在想:这对性能来说真的很糟糕吗?每次消费者的状态更新时,所有的树都必须重建。然后我意识到到处都是const
限定符。这看起来是一个非常整洁的设置。我决定调试它,看看何时何地重建小部件。
当应用程序第一次启动时,flutter会沿着树一个接一个地构建小部件,这是有道理的。
当单击按钮并递增Counter
时,builder
在树的最顶部的Consumer上被调用。之后,build
在CounterLabel
和IncrementCounterButton
上被调用。CounterLabel
是有意义的。这不是const
,实际上会改变它的内容。但是IncrementCounterButton
被标记为const
。为什么它会重建?
我不太清楚为什么有些const
小部件被重建了,而另一些却没有。这背后的系统是什么?
3条答案
按热度按时间huus2vyu1#
小部件重建的最常见原因是:
小部件的Const示例不受第一个原因的影响,但它们仍然受到其他两个原因的影响。
这意味着一个StatelessWidget的const示例将 * 仅 * 在它使用更新的继承小部件之一时重建。
qyswt5oh2#
Provider是InheritedWidget的一个方便的 Package 器,为您做了很多好的事情。
因为
IncrementCounterButton
访问Provider(以及底层的InheritedWidget),所以每当数据发生更改时,它都会侦听并重新构建。要防止按钮或其他不需要在数据更改时重建的小部件,请将
listen
设置为false
。Provider.of(context,listen:false).increment
需要注意的是,如果根部件重新生成,标记为
listen: false
的部件仍将重新生成。Understand how listen: false works when used with Provider.of(context, listen: false)希望这有帮助!
dffbzjpn3#
基于@RayLi和@Remi的回答,另一种防止重建的方法是进行以下修改:
字符串
context.read()
不会更新,但在这种情况下,这是你想要的。onPressed
将Map到.increment
的同一个示例在整个浮动按钮的存在。context.read<Counter>()
与Provider.of<Counter>(context, listen: false)
具有相同的行为。参见Is Provider.of(context, listen: false) equivalent to context.read()?