是否有一种方法可以防止多次调用build()
?
下一个代码创建两个页面,每个页面都有一个按钮,FirstPage
上的按钮导航到SecondPage
,而SecondsPage
上的按钮返回到FirstPage
。 / p>
问题在于,如果您单击FirstPage
上的按钮,它将运行SecondPage
build()
,但也会运行FirstPage
build()
。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'First page',
home: FirstPage(),
);
}
}
class FirstPage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _FirstPageState();
}
}
class _FirstPageState extends State<FirstPage> {
@override
Widget build(BuildContext context) {
print('---------- In FirstPage build ----------');
return Scaffold(
appBar: AppBar(
title: Text('First page'),
),
body: Column(
children: [
Text('First page body'),
FlatButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
},
child: Text('Go to second page')
)
]
)
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('---------- In SecondPage build ----------');
return Scaffold(
appBar: AppBar(
title: Text('Second page'),
),
body: Column(
children: [
Text('Second page body'),
FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back')
)
]
)
);
}
}
控制台输出:
Performing hot restart...
D/dalvikvm(23908): threadid=12: interp stack at 0x76040000
Restarted app in 3,849ms.
I/flutter (23908): ---------- In FirstPage build ----------
I/SurfaceTextureClient(23908): [STC::queueBuffer] (this:0x76b39810) fps:0.07, dur:14731.13, max:14731.13, min:14731.13
I/SurfaceTextureClient(23908): [STC::queueBuffer] this:0x76b39810, api:1, last queue time elapsed:14731.13
点击按钮后:
V/Provider/Settings(23908): from db cache, name = sound_effects_enabled , value = 0
I/flutter (23908): ---------- In SecondPage build ----------
I/SurfaceTextureClient(23908): [STC::queueBuffer] (this:0x76b39810) fps:0.24, dur:4140.60, max:4140.60, min:4140.60
I/flutter (23908): ---------- In FirstPage build ----------
感谢您的帮助。
编辑:
我尝试在popAndPushNamed()
上使用FirstPage
,它只是在SecondPage
上运行构建,但是如果我尝试返回:
Navigator.popAndPushNamed(
context,
'/'
);
我得到了错误:
I/flutter ( 5005): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter ( 5005): The following assertion was thrown while handling a gesture:
I/flutter ( 5005): Cannot reuse a MaterialPageRoute<dynamic> after disposing it.
I/flutter ( 5005): 'package:flutter/src/widgets/routes.dart': Failed assertion: line 215 pos 12:
I/flutter ( 5005): '!_transitionCompleter.isCompleted'
I/flutter ( 5005): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 5005): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 5005): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 5005): https://github.com/flutter/flutter/issues/new
I/flutter ( 5005): When the exception was thrown, this was the stack:
I/flutter ( 5005): #2 TransitionRoute.didPopNext (package:flutter/src/widgets/routes.dart)
I/flutter ( 5005): #3 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:1691:23)
I/flutter ( 5005): #4 NavigatorState.popAndPushNamed (package:flutter/src/widgets/navigator.dart:1399:5)
I/flutter ( 5005): #5 Navigator.popAndPushNamed (package:flutter/src/widgets/navigator.dart:731:34)
I/flutter ( 5005): #6 SecondPage.build.<anonymous closure> (file:///home/ncs/Documents/flutter/src/test1/lib/main.dart:83:25)
I/flutter ( 5005): #7 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:494:14)
I/flutter ( 5005): #8 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:549:30)
I/flutter ( 5005): #9 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
I/flutter ( 5005): #10 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:161:9)
I/flutter ( 5005): #11 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:94:7)
I/flutter ( 5005): #12 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
I/flutter ( 5005): #13 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
I/flutter ( 5005): #14 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
I/flutter ( 5005): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
I/flutter ( 5005): #16 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
I/flutter ( 5005): #17 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
I/flutter ( 5005): #18 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
I/flutter ( 5005): #19 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
I/flutter ( 5005): #20 _invoke1 (dart:ui/hooks.dart:134:13)
I/flutter ( 5005): #21 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:5)
I/flutter ( 5005): (elided 2 frames from class _AssertionError)
I/flutter ( 5005): Handler: onTap
I/flutter ( 5005): Recognizer:
I/flutter ( 5005): TapGestureRecognizer#94626(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
I/flutter ( 5005): Offset(65.3, 119.6), sent tap down)
I/flutter ( 5005): ════════════════════════════════════════════════════════════════════════════════════════════════════
我能够删除不想要的版本的唯一方法是通过以下条件::
class _FirstPageState extends State<FirstPage> {
bool _canBuild = true;
@override
Widget build(BuildContext context) {
if (!_canBuild) {
return Container();
}
print('---------- In FirstPage build ----------');
...
onPressed: () {
_canBuild = false;
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
).then((_) {
_canBuild = true;
});
},
...
这是不好的做法还是会造成任何问题?
答案 0 :(得分:0)
这仅仅是因为小部件仍在路由栈中。我认为颤动会重新渲染堆栈中的小部件。如果在路由到SecondPage之前弹出FirstPage,它将不会显示第一个小部件的消息。
编辑:
如何使用。
pip install tensorflow
答案 1 :(得分:0)
Flutter总是在每次按下/弹出后在导航堆栈中构建每个“页面”(小部件)。这是正常的和预期的行为,因此每个窗口小部件都可以在需要时自行更新。
小部件的构建方法应该是幂等的,尽管通常仅在您认为会构建时才构建,但框架可能出于任何原因在任何时候决定构建小部件-您不能依赖任何未构建的小部件。
通常这实际上不是问题,Flutter会将所有新的窗口小部件与构建中的所有旧窗口小部件进行比较,如果窗口小部件相同,则它们将不会被替换或以任何其他方式受到影响。
因此,简短的答案是“否”,当然,如果您愿意,可以解决此问题(例如,通过覆盖导航器),那么您绝对可以。
您可以在此处查看与构建窗口小部件(包括导航器)的子代相关的代码:https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart
但是理想情况下,您只是想假设任何东西都可以随时构建-可以。 Flutter不保证何时(或将不会)构建您的窗口小部件,任何未考虑到这一点的代码都容易被破坏!
答案 2 :(得分:-1)
我也面临着同样的问题。然后,我使用pushNamed()
而不是popAndPushNamed()
Navigator.popAndPushNamed(context,'/');
我不知道原因,但是它在起作用!