问题描述
这是我正在制作的应用程序的登录代码。我想更新我在发布请求后得到的 parent_inherit(Inherited Widget) 中的令牌。 Inherited widget(parent_inherit) 中的令牌值。
Future<void> attemptLogIn(String username,String password,BuildContext context) async {
String parentToken= parent_inherit.of(context);
SharedPreferences prefs = await SharedPreferences.getInstance();
print("$username $password");
final http.Response res = await http.post(
"..............the route.............",headers: <String,String>{
'Content-Type': 'application/json; charset=UTF-8',},body: jsonEncode(<String,String>{
"email": username,"password": password
}),);
if(res.statusCode == 200) {
prefs.setString('jwt',res.body);
var value=prefs.getString('jwt');
Map<String,dynamic> valueMap=jsonDecode(value);
TokenClass token=TokenClass.fromJson(valueMap);
parentToken=token.token;// I was trying something like this,but it seems to not work
Navigator.of(context).pushNamed('/home');
}
else{
return _showMyDialoglogin(context,res.statusCode);
}
}
另外,在上面的文件中,当我在上面声明 parentToken 并使用它时,它仍然显示上面声明的 parentToken 没有被使用。当我将鼠标悬停在它上面时它也会显示警告。为什么会这样?
parent_inherit.dart
class parent_inherit extends InheritedWidget {
final String token;
const parent_inherit({
Key key,@required this.token,Widget child})
:super(key:key,child: child);
@override
bool updateShouldNotify(parent_inherit oldWidget) =>true;
static String of(BuildContext context) => context.dependOnInheritedWidgetofExactType<parent_inherit>().token;
}
TokenClass.dart
class TokenClass{
final String token;
TokenClass(this.token);
TokenClass.fromJson(Map<String,dynamic> json)
: token=json['token'];
}
我的主要功能 - 在主要功能中,令牌值存在问题,无法正确更新和获取继承小部件内外的值。有时它也使用以前的令牌值。
main.dart
bool checkingKey;
String tokenName;
TokenClass token;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Paint.enableDithering = true;
const defaultJson = '{}';
var prefs = await SharedPreferences.getInstance();
checkingKey = prefs.containsKey("jwt");
tokenName=prefs.getString('jwt');
Map<String,dynamic> valueMap = jsonDecode(tokenName??defaultJson);
token=TokenClass.fromJson(valueMap);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return parent_inherit(
token: checkingKey==false?'':token.token,child: MaterialApp(
home: AnnotatedRegion<systemUIOverlayStyle>(
value: systemUIOverlayStyle(
statusBarColor: Colors.transparent,),child: Scaffold(
resizetoAvoidBottomInset: false,body: Container(
color: Color(0xffccffcc),child: !checkingKey ? LoginPage() : mainPage(),routes: <String,WidgetBuilder>{
'/home':(BuildContext context) => mainPage(),'/login':(BuildContext context) => LoginPage(),);
}
}
也欢迎其他建议...
解决方法
更新 InheritedWidget
的一种方法是使用 Notification
。
首先,我们有我们的通知类:
class LoginNotification extends Notification {
final TokenClass token;
LoginNotification(this.token);
}
然后我们用通知侦听器包装 parent_inherit
:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return NotificationListener<LoginNotification>(
onNotification: (loginNotification) {
setState(() {
token = loginNotification.token;
checkingKey = true;
});
return true;
},child: parent_inherit(
token: checkingKey ? token.token : '',child: MaterialApp(
home: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: Colors.transparent,),child: Scaffold(
resizeToAvoidBottomInset: false,body: Container(
color: Color(0xffccffcc),child: checkingKey ? MainPage() : LoginPage(),routes: <String,WidgetBuilder>{
'/home': (BuildContext context) => MainPage(),'/login': (BuildContext context) => LoginPage(),},);
}
}
在 attemptLogIn
方法中,你只需要发送一个通知:
Future<void> attemptLogIn(
String username,String password,BuildContext context) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (kDebugMode) print("$username $password");
final http.Response res = await http.post(
"..............the route.............",headers: <String,String>{
'Content-Type': 'application/json; charset=UTF-8',body: jsonEncode(<String,String>{"email": username,"password": password}),);
if (res.statusCode == 200) {
// check if the login is valid first
//...
prefs.setString('jwt',res.body);
var value = prefs.getString('jwt');
Map<String,dynamic> valueMap = jsonDecode(value);
TokenClass token = TokenClass.fromJson(valueMap);
// send notification to a LoginNotification Listener
LoginNotification(token).dispatch(context);
Navigator.of(context).pushNamed('/home');
} else {
return _showMyDialoglogin(context,res.statusCode);
}
}
如您所见,使用 InheretedWidget
并不容易,而且所有这些都是针对单个值的。
也许可以考虑其他状态管理解决方案,我没有任何特别的建议,但 Flutter 文档列出了最常用的解决方案 here。