在构建方法中声明变量是一种不好的做法吗
Is it a bad practice to declare variables in build method
我正在开发音乐播放器应用程序。我必须检索每首歌曲的缩略图、名称、作者等数据。所以我在构建方法
的 return 上方使用了以下代码
...@override
Widget build(BuildContext context) {
//For song index and details
final themeNotifier = Provider.of<ThemeNotifier>(context, listen: true);
audioFunctions = themeNotifier.getAudioFunctions();
themeNotifier.getSongIndex().then((value) {
setState(() {
index = value;
});
});
thumbnailPath =
audioFunctions.songs[index].albumArtwork ?? 'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
return Scaffold(...
这是一种不好的做法吗?如果是这样,我怎样才能正确地做到这一点?
对于任何类型的小部件,您很可能需要一些准备工作(例如设置变量的初始值或向 FocusNode
添加侦听器)。
也就是说,对于 StatelessWidget
我还没有找到任何方法来做到这一点,然后在 build
函数的开头这样做。
对于 StatefulWidget
,您可以通过覆盖 initState
方法来完成所有这些操作。您通常会在此处设置侦听器或设置 TextEditingController
.
的初始值
对于任何需要在渲染之前等待一些 Future
的小部件,我会推荐 FutureBuilder
因为这很容易让你处理所有不同的 snapshot
条件和/或 ConnectionState
.
对于你的情况,我没有发现
之类的问题
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
因为您可以将这些视为只是为原本很长的表达式制作的一种缩写。例如,与 Theme.of(context).primaryColorLight
.
相比,重复写 light
会容易得多
然而,对于这样的事情
themeNotifier.getSongIndex().then((value) {
setState(() {
index = value;
});
});
根据 getSongIndex()
的具体作用、可能导致的错误或延迟类型,您可能需要考虑其他选项,例如 FutureBuilder
.
是的。
根据 Flutter Docs:
Although it’s convenient, it’s not recommended to put an API call in a build() method.
Flutter calls the build() method every time it needs to change anything in the view, and this happens surprisingly often. Leaving the fetch call in your build() method floods the API with unnecessary calls and slows down your app.
解决方法:
要么像这样使用 FutureBuilder
小部件:
class _MyAppState extends State<MyApp> {
Future<int> songIndex;
@override
void didChangeDependencies(){
songIndex = Provider.of<ThemeNotifier>(context, listen: false).getSongIndex();
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
return FutureBuilder<int>(
future: songIndex,
builder: (context, snapshot) {
if (snapshot.hasData) {
final index = snapshot.data;
thumbnailPath = audioFunctions.songs[index].albumArtwork ??
'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
return Scaffold(body: Container());
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
);
}
}
注意:
final themeNotifier = Provider.of<ThemeNotifier>(context, listen: false);
listen 是 false
因为我认为我们不需要在每次提供程序更改其状态时重建小部件(因为我们仅将其用于执行方法)。
或者 [更好的方法] 将逻辑放在 ThemeNotifier
class 中。
像这样:
在主题通知器中class:
class ThemeNotifier with ChangeNotifier {
//whatever state and logic you have
//state for you current song index
int _index;
int get index => _index;
Future<void> getSongIndex() {
// some logic to retreive the new index
_index = newIndex;
notifyListeners();
}
}
在您提供的地方 ThemeNotifier
Widget build() => ChangeNotifierProvider(
create: (_) => ThemeNotifier()..getSongIndex(),
child: //whatever,
);
在你使用(消费)的地方:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
return Consumer<ThemeNotifier>(
builder: (context, themeNotifier, _) {
final index = themeNotifier.index;
if (index == null) return CircularProgressIndicator();
thumbnailPath =
audioFunctions.songs[index].albumArtwork ?? 'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
return Scaffold(
body: // continue here,
);
},
);
}
}
这是使用 Consumer
语法,如果您不想在这种情况下每次提供商调用 notifyListeners()
时重建整个 MyApp
小部件,这种语法会更好。但如果重建无关紧要(如本例),更简单的方法是:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
final themeNotifier = Provider.of<ThemeNotifier>(context);
final index = themeNotifier.index;
if (index == null) return CircularProgressIndicator();
thumbnailPath =
audioFunctions.songs[index].albumArtwork ?? 'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
return Scaffold(body: null // continue here,
);
}
}
最后的想法:
我建议你提取这个逻辑:
thumbnailPath = audioFunctions.songs[index].albumArtwork ??
'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
进入提供商本身。
我正在开发音乐播放器应用程序。我必须检索每首歌曲的缩略图、名称、作者等数据。所以我在构建方法
的 return 上方使用了以下代码...@override
Widget build(BuildContext context) {
//For song index and details
final themeNotifier = Provider.of<ThemeNotifier>(context, listen: true);
audioFunctions = themeNotifier.getAudioFunctions();
themeNotifier.getSongIndex().then((value) {
setState(() {
index = value;
});
});
thumbnailPath =
audioFunctions.songs[index].albumArtwork ?? 'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
return Scaffold(...
这是一种不好的做法吗?如果是这样,我怎样才能正确地做到这一点?
对于任何类型的小部件,您很可能需要一些准备工作(例如设置变量的初始值或向 FocusNode
添加侦听器)。
也就是说,对于 StatelessWidget
我还没有找到任何方法来做到这一点,然后在 build
函数的开头这样做。
对于 StatefulWidget
,您可以通过覆盖 initState
方法来完成所有这些操作。您通常会在此处设置侦听器或设置 TextEditingController
.
对于任何需要在渲染之前等待一些 Future
的小部件,我会推荐 FutureBuilder
因为这很容易让你处理所有不同的 snapshot
条件和/或 ConnectionState
.
对于你的情况,我没有发现
之类的问题//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
因为您可以将这些视为只是为原本很长的表达式制作的一种缩写。例如,与 Theme.of(context).primaryColorLight
.
light
会容易得多
然而,对于这样的事情
themeNotifier.getSongIndex().then((value) {
setState(() {
index = value;
});
});
根据 getSongIndex()
的具体作用、可能导致的错误或延迟类型,您可能需要考虑其他选项,例如 FutureBuilder
.
是的。 根据 Flutter Docs:
Although it’s convenient, it’s not recommended to put an API call in a build() method.
Flutter calls the build() method every time it needs to change anything in the view, and this happens surprisingly often. Leaving the fetch call in your build() method floods the API with unnecessary calls and slows down your app.
解决方法:
要么像这样使用 FutureBuilder
小部件:
class _MyAppState extends State<MyApp> {
Future<int> songIndex;
@override
void didChangeDependencies(){
songIndex = Provider.of<ThemeNotifier>(context, listen: false).getSongIndex();
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
return FutureBuilder<int>(
future: songIndex,
builder: (context, snapshot) {
if (snapshot.hasData) {
final index = snapshot.data;
thumbnailPath = audioFunctions.songs[index].albumArtwork ??
'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
return Scaffold(body: Container());
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
);
}
}
注意:
final themeNotifier = Provider.of<ThemeNotifier>(context, listen: false);
listen 是 false
因为我认为我们不需要在每次提供程序更改其状态时重建小部件(因为我们仅将其用于执行方法)。
或者 [更好的方法] 将逻辑放在 ThemeNotifier
class 中。
像这样:
在主题通知器中class:
class ThemeNotifier with ChangeNotifier {
//whatever state and logic you have
//state for you current song index
int _index;
int get index => _index;
Future<void> getSongIndex() {
// some logic to retreive the new index
_index = newIndex;
notifyListeners();
}
}
在您提供的地方 ThemeNotifier
Widget build() => ChangeNotifierProvider(
create: (_) => ThemeNotifier()..getSongIndex(),
child: //whatever,
);
在你使用(消费)的地方:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
return Consumer<ThemeNotifier>(
builder: (context, themeNotifier, _) {
final index = themeNotifier.index;
if (index == null) return CircularProgressIndicator();
thumbnailPath =
audioFunctions.songs[index].albumArtwork ?? 'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
return Scaffold(
body: // continue here,
);
},
);
}
}
这是使用 Consumer
语法,如果您不想在这种情况下每次提供商调用 notifyListeners()
时重建整个 MyApp
小部件,这种语法会更好。但如果重建无关紧要(如本例),更简单的方法是:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//For the bg-gradient and device height
double deviceHeight = MediaQuery.of(context).size.height;
final light = Theme.of(context).primaryColorLight;
final dark = Theme.of(context).primaryColorDark;
final themeNotifier = Provider.of<ThemeNotifier>(context);
final index = themeNotifier.index;
if (index == null) return CircularProgressIndicator();
thumbnailPath =
audioFunctions.songs[index].albumArtwork ?? 'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
return Scaffold(body: null // continue here,
);
}
}
最后的想法: 我建议你提取这个逻辑:
thumbnailPath = audioFunctions.songs[index].albumArtwork ??
'assets/thumbnail.jpg';
title = audioFunctions.optimiseSongTitles(index) ?? title;
author = audioFunctions.songs[index].artist ?? author;
进入提供商本身。