处理此问题的正确方法是什么,我已经进行了很多搜索,并且大多数使用将来的构建器的示例都使用它们来绘制列表,所以也许我应该在这里避免全部使用它们。
我想在登录时(如果成功浏览到主页)提交登录表单,执行网络请求并绘制进度栏。如果不成功,则应终止进度条并重新绘制主页。该部分似乎正常工作,不确定我是否正确使用了导航器。
登录调用返回用户和访问令牌对象。主页需要检索成功登录响应写入数据库的访问令牌。据我所知,导航进行得太快了,访问令牌的检索似乎发生在导航至主页之前。
class LoginPage extends StatefulWidget {
LoginPage({Key key, this.title}) : super(key: key);
final String title;
@override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool _isValidForm = true;
Future<LoginResponse> _user;
void _submitLogin() {
setState(() {
if (_isValidForm) {
_user = login().then((_) => Navigator.push(context, MaterialPageRoute(builder: (context) => HomePage())));
}
});
}
Widget _buildLoginForm(AsyncSnapshot<LoginResponse> snapshot) {
if (snapshot.connectionState != ConnectionState.none && !snapshot.hasData) {
return new Center(child: new CircularProgressIndicator());
} else {
return SafeArea(
child: Center(
child: new ListView(
children: <Widget>[
//..more views
Padding(
padding: EdgeInsets.fromLTRB(16.0, 0.0, 16.0, 16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//..email and password fields
FlatButton(
child: new Text(
'SIGN IN',
),
onPressed: _submitLogin),
]),
)
],
),
),
);
}
}
@override
Widget build(BuildContext context) {
return new FutureBuilder(
future: _user,
builder: (context, AsyncSnapshot<LoginResponse> snapshot) {
return new Scaffold(
backgroundColor: kMyGreen,
body: _buildLoginForm(snapshot),
);
},
);
}
Future<LoginResponse> login() async {
final response = await http.post(...);
if (response.statusCode == 200) {
var loginResponse = LoginResponse.fromJson(json.decode(response.body));
//Write the user details to local db
DBProvider.db.newUser(loginResponse.user);
//Write the tokens to local db
DBProvider.db.newToken(loginResponse.tokens);
return loginResponse;
} else {
throw Exception('Failed to login');
}
}
}
数据库方法:
newUser(User newUser) async {
final db = await database;
//get the biggest id in the table
var table = await db.rawQuery("SELECT MAX(id)+1 as id FROM User");
int id = table.first["id"];
//insert to the table using the new id
var raw = await db.rawInsert(
"INSERT Into User (id,first_name,last_name)"
" VALUES (?,?,?)",
[id, newUser.firstName, newUser.lastName]);
return raw;
}
newToken(Tokens newTokens) async {
final db = await database;
//await db.rawDelete("DELETE FROM Token");
//get the biggest id in the table
var table = await db.rawQuery("SELECT MAX(id)+1 as id FROM Token");
int id = table.first["id"];
//insert to the table using the new id
var raw = await db.rawInsert(
"INSERT Into Token (id,access_token,refresh_token)"
" VALUES (?,?,?)",
[id, newTokens.accessToken, newTokens.refreshToken]);
return raw;
}
Future<Tokens> getToken() async {
final db = await database;
var res = await db.query("Token", limit: 1);
return res.isNotEmpty ? Tokens.fromJson(res.first) : null;
}
主页
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>{
@override
void initState() {
super.initState();
getHomePageStuff();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
),
body: Center(
child: RaisedButton(
onPressed: () {},
child: Text('Go back!'),
),
),
);
}
}
Future<HomePageStuffResponse> getHomePageStuff() async {
Tokens token = await DBProvider.db.getToken();
//Accessing the token here throws an NPE
var accessToken = token.accessToken;
debugPrint("token = " + accessToken);
final response = await http.get(..);
if (response.statusCode == 200) {
debugPrint("FETCH SUCCESS");
return stuff;
} else {
throw Exception('Failed to fetch home page stuff');
}
}
答案 0 :(得分:1)
您可以像这样将angular.json
主体包裹在Scaffold's
中
FutureBuilder
答案 1 :(得分:0)
好的,我离得很近。导航是一种很好的方式,问题在于未await
写入数据库,因此导航会同时发生(newUser
和newToken
调用)。当我导航到主屏幕并尝试读取访问令牌时,呼叫将失败,因为该呼叫尚不存在。
很难弄清这一点,因为调试器在Android Studio中有些混乱,因此我只需要将所有内容都记录到控制台即可查看问题。
如果您阅读我的问题,谢谢您的时间:)