【发布时间】:2020-12-12 20:30:36
【问题描述】:
总结:
当使用导航器显示页面/路由时,会从最近的MaterialApp 父级创建一个新分支。这意味着两个页面(Main 和New)都将在内存中,如果它们正在收听相同的ChangeNotifier,它们将重建。
我无法找出屏幕上当前对用户可见的小部件。 我需要它来处理一个场景,以跳过可能在小部件树中但当前不可见的小部件执行具有一些副作用的异步或长进程。
注意:此处给出的示例代码代表了我当前正在开发的应用程序的基本架构,但重现了确切的问题。
我的应用程序中有一个非常不同且复杂的小部件树,它从屏幕上不可见的小部件执行doLongProcess(),因此我遇到了这个问题。此外,doLongProcess() 更改了我的应用程序中的一些常见属性,这会导致问题,因为任何背景小部件都可以修改其他小部件上可见的详细信息。
我正在寻找解决此问题的方法,如果除了查找屏幕上的小部件之外还有其他方法可以实现该目标,那么也请告诉我。
我的最终目标是只允许从可见的小部件执行漫长的过程。
请运行该应用程序一次,以正确理解以下详细信息。
注意 2:
我尝试使用状态的mounted 属性来确定它是否可以使用,但它对于两个小部件(MainPage TextDisplay 和NewPage TextDisplay)都显示为true
如果有更多详细信息或我遗漏了需要的内容,请在 cmets 中告诉我。
使用以下示例代码包含provider 依赖项 来重现问题:
// add in pubspec.yaml: provider: ^4.3.2+1
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
print('MainPage: build');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextDisplay(
name: 'MainPage TextDisplay',
),
SizedBox(
height: 20,
),
RaisedButton(
child: Text('Open New Page'),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => NewPage(),
)),
),
],
),
),
);
}
}
class TextDisplay extends StatefulWidget {
final String name;
const TextDisplay({Key key, @required this.name}) : super(key: key);
@override
_TextDisplayState createState() => _TextDisplayState();
}
class _TextDisplayState extends State<TextDisplay> {
@override
Widget build(BuildContext context) {
return Container(
child: ChangeNotifierProvider.value(
value: dataHolder,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(child: Text(widget.name)),
SizedBox(
height: 20,
),
Consumer<DataHolder>(
builder: (context, holder, child) {
// need to detect if this widget is on the screen,
// only then we should go ahead with this long process
// otherwise we should skip this long process
doLongProcess(widget.name);
return Text(holder.data);
},
),
RaisedButton(
child: Text('Randomize'),
onPressed: () => randomizeData(),
),
],
),
),
);
}
void doLongProcess(String name) {
print('$name: '
'Doing a long process using the new data, isMounted: $mounted');
}
}
class NewPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('NewPage: build');
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
title: Text('New Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextDisplay(
name: 'NewPage TextDisplay',
),
],
),
),
);
}
}
/////////////////// Data Holder Class and methods ///////////////////
class DataHolder extends ChangeNotifier {
String _data;
String get data => _data ?? 'Nothing to show, Yet!';
setData(String newData) {
print('\n new data found: $newData');
_data = newData;
notifyListeners();
}
}
final dataHolder = DataHolder();
randomizeData() {
int mills = DateTime.now().millisecondsSinceEpoch;
dataHolder.setData(mills.toString());
}
【问题讨论】:
标签: flutter flutter-navigation flutter-widget