Простой Flutter sqflite вход в систему-> запись в БД-> навигация-> получить из потока БД - PullRequest
0 голосов
/ 10 марта 2019

Какой правильный способ справиться с этим, я провел большой поиск, и большинство примеров, которые используют будущие сборщики, используют их для составления списков, поэтому, возможно, мне следует избегать их всех вместе здесь.

Я хочу отправить форму входа в систему, выполнить сетевой запрос и нарисовать индикатор выполнения во время входа в систему, и в случае успеха перейдите на домашнюю страницу. В случае неудачи он должен просто убить индикатор выполнения и перерисовать домашнюю страницу. Эта часть, кажется, работает, не уверен, правильно ли я использую Навигатор.

Вызов входа возвращает пользователя и объект токена доступа. Домашняя страница должна получить токен доступа, который был записан в базу данных в результате успешного входа в систему. Из того, что я могу сказать, навигация происходит слишком быстро, и получение маркера доступа происходит до перехода на домашнюю страницу.

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');
  }
}

Ответы [ 2 ]

1 голос
/ 10 марта 2019

Вы можете просто обернуть Scaffold's тело в FutureBuilder вот так

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Home Page"),
      ),
      body: FutureBuilder<HomePageStuffResponse>(
        future: getHomePageStuff(),
        builder: (context, snap) {
          if(snap.hasError) {
            return ErrorWidget('Error occurred while fetching data');
          }
          if(snap.hasData) {
            return 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 голосов
/ 11 марта 2019

Хорошо, я был довольно близко.Навигация в порядке, проблема была в том, что запись в базу данных не await редактировалась, так что это происходило бы одновременно с навигацией (вызовы newUser и newToken).Поскольку я переходил на домашний экран и пытался прочитать токен доступа, вызов не состоялся бы, потому что он еще не существовал.

Это было немного сложнее понять, потому что отладчик немного странный в AndroidСтудия для трепетания, поэтому мне просто нужно было записать все на консоль, чтобы увидеть проблему.

Если вы прочитали мой вопрос, спасибо за ваше время:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...