我正在使用InheritedWidget来跟踪身份验证状态。它可以在主应用程序上正常工作。但是,一旦我通过路由更改转到另一个页面,新路由中的组件就找不到继承的窗口小部件。
理想情况下,我希望所有页面/路由都共享相同的身份验证状态。
下面的最小示例给出了NULL指针错误。
import 'package:flutter/material.dart';
void main() => runApp(EntryPoint());
class TestContext extends InheritedWidget {
const TestContext({
Key key,
Widget child,
}) : super(key: key, child: child);
final String hello = "foobar";
static TestContext of(BuildContext context) {
return context.inheritFromWidgetOfExactType(TestContext) as TestContext;
}
@override
bool updateShouldNotify(TestContext oldWidget) => true;
}
class EntryPoint extends StatelessWidget {
/// Needed for dialog
final navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey,
title: 'TODO',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TestContext(
child: Scaffold(
body: Center(
child: Builder(
builder: (context) => FlatButton(
child: Text('Launch'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginForm()),
);
}))))));
}
}
class LoginForm extends StatefulWidget {
@override
LoginFormState createState() {
return LoginFormState();
}
}
class LoginFormState extends State<LoginForm> {
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Scaffold(
body: Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Enter your JIRA website URL'),
keyboardType: TextInputType.url,
textInputAction: TextInputAction.next,
style: TextStyle(
fontSize: 28,
initialValue: TestContext.of(context).hello,
),
],
)),
));
}
}
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building LoginForm(dirty, state: LoginFormState#be3a1):
The getter 'hello' was called on null.
Receiver: null
Tried calling: hello
User-created ancestor of the error-causing widget was
MaterialApp
package:flutter_greeting_screen/main.dart:63
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 LoginFormState.build
package:flutter_greeting_screen/main.dart:144
答案 0 :(得分:0)
当您使用Navigator.of(context).push(...)
或Navigator.push(context, ...)
或Navigator.of(context).pushNamed(...)
或Navigator.pushNamed(context, ...)
时,推入的小部件不是调用Navigator.push
的小部件的子级(及其变体),则此小部件是Navigator
的最接近实例的子级,该实例包含给定的context
,在您的情况下,Navigator
由MaterialApp
创建,因此如果要为所有路由提供TestContext
,InheritedWidget
必须是Navigator
的父级,在您的情况下必须是MaterialApp
的父级。
class EntryPoint extends StatelessWidget {
/// Needed for dialog
final navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return TestContext(
child: MaterialApp(
navigatorKey: navigatorKey,
title: 'TODO',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Center(
child: Builder(
builder: (context) => FlatButton(
child: Text('Launch'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginForm()),
);
}))))),
);
}
}
我还建议您查看provider程序包的Provider
小部件,它是带有InheritedWidget
语法糖的小部件。
InheritedWidget的通用实现。它允许公开任何类型的对象,而无需自己手动编写InheritedWidget。
Provider<String>.value(
value: 'Hello World',
child: MaterialApp(
home: Home(),
)
)
Provider<Auth>(
builder: (context) => Auth(),
dispose: (context, auth) => auth.dispose(),
child: MaterialApp(
home: Home(),
)
)