setState не обновляет интерфейс - PullRequest
1 голос
/ 05 марта 2020

Я пытаюсь получить данные из API, и я могу получить журналы, но setState не работает. В целом, чего я хочу добиться, так это, если есть ответ, покажите данные на экране, если есть какая-либо ошибка в API или на сервере, или что-либо еще, что я хочу показать в снэк-баре. Мой девиз также показывает ошибки.

Ниже приведен класс моей модели

import 'http.dart';

class User {
int userId;
int id;
String title;
String body;

User({this.userId, this.id, this.title, this.body});

User.fromJson(Map<String, dynamic> json) {
  userId = json['userId'];
  id = json['id'];
  title = json['title'];
  body = json['body'];
}

Map<String, dynamic> toJson() {
  final Map<String, dynamic> data = new Map<String, dynamic>();
  data['userId'] = this.userId;
  data['id'] = this.id;
  data['title'] = this.title;
  data['body'] = this.body;
  return data;
}


}


class UserExt {

static getUserInfo(Function(User user) success, Function(String errorMesssage) error) async{

  final response = await HTTP.get(api: "https://jsonplaceholder.typicode.com/posts/1");
  if(response.isSuccess == true) {
    success(User.fromJson(response.response));
  } else {
    error(response.response);
  }

}

}

Ниже приведен мой файл http.dart

import 'dart:html';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as convert;
import 'package:http/http.dart';

const _timeoutDuration = Duration(seconds: 5);

class HTTP {


  static Future<HttpResponse> get({@required String api}) async {

    try {
      Response response = await http.get(api).timeout(_timeoutDuration);
      return _modeledResponse(response);
    } catch (error) {
      return HttpResponse(isSuccess: false, response: error.toString());
    }


  }

  static Future<HttpResponse> _modeledResponse(Response response) async {

    try {
      if(response.statusCode == HttpStatus.ok) {
        var jsonResponse = convert.jsonDecode(response.body);
        return HttpResponse(isSuccess: true, response: jsonResponse);
      } else {
        return HttpResponse(isSuccess: false, response: response.statusCode.toString());
      }
    } catch (error) {
      return HttpResponse(isSuccess: false, response: error.toString());
    }

  }



}




class HttpResponse {
  final bool isSuccess;
  final dynamic response;
  HttpResponse({@required this.isSuccess, @required this.response});
}

Ниже мой экран, откуда я вызываю API.

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http_request/User.dart';
import 'http.dart';






class ApiCalling extends StatefulWidget {
  @override
  _ApiCallingState createState() => _ApiCallingState();
}

class _ApiCallingState extends State<ApiCalling> {

  bool showLoader = false;

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: Center(
        child: Stack(
          children: <Widget>[


            Center(
              child: RaisedButton(
                child: Text("Call API"),
                onPressed: () {

                  setState(() {
                    showLoader = true;
                  });
                  UserExt.getUserInfo((user){
                    print("UUUser id = ${user.userId}");
                    Scaffold.of(context).showSnackBar(SnackBar(content:     Text("${user.userId}"),));

                setState(() {
                  showLoader = false;
                });


              }, (error){
                Scaffold.of(context).showSnackBar(SnackBar(content: Text("${error}"),));
                setState(() {
                  showLoader = false;
                });
              });


            },
          ),
        ),
        Visibility(child: CircularProgressIndicator(backgroundColor: Colors.pink,), visible: showLoader,),


      ],
    ),
  ),
);
  }
}

В текущем коде индикатор не получает показ / скрытие или снэк-бар также не отображается.

Ответы [ 3 ]

2 голосов
/ 05 марта 2020

Только что внесли некоторые изменения и дополнения, просто проверьте следующий код:

import 'package:flutter/material.dart';
import 'package:sample_project_for_api/model.dart';

void main() => runApp(ApiCalling());

class ApiCalling extends StatefulWidget {
  @override
  _ApiCallingState createState() => _ApiCallingState();
}

class _ApiCallingState extends State<ApiCalling> {
  bool showLoader = false;
  final _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        key: _scaffoldKey,
        body: Center(
          child: Stack(
            children: <Widget>[
              Builder(
                builder: (context) {
                  return Column(
                    children: <Widget>[
                      RaisedButton(
                        child: Text(
                            "this is first api call under the builder widget"),
                        onPressed: () {
                          UserExt.getUserInfo((user) {
                            print("UUUser id = ${user.userId}");
                            Scaffold.of(context).showSnackBar(SnackBar(
                              backgroundColor: Colors.redAccent,
                              content:
                                  Text("This is you user id ${user.userId}"),
                            ));
                          }, (error) {
                            Scaffold.of(context).showSnackBar(SnackBar(
                              duration: Duration(seconds: 2),
                              backgroundColor: Colors.redAccent,
                              content: Text("${error.toString()}"),
                            ));
                          });
                        },
                      ),
                      RaisedButton(
                        child: Text(
                            "this is second api call under the builder widget"),
                        onPressed: () {
                          UserExt.getUserInfo((user) {
                            print("UUUser id = ${user.userId}");
                            Scaffold.of(context).showSnackBar(SnackBar(
                              backgroundColor: Colors.redAccent,
                              content:
                                  Text("This is you user id ${user.userId}"),
                            ));
                          }, (error) {
                            Scaffold.of(context).showSnackBar(SnackBar(
                              duration: Duration(seconds: 2),
                              backgroundColor: Colors.redAccent,
                              content: Text("${error.toString()}"),
                            ));
                          });
                        },
                      )
                    ],
                  );
                },
              ),
              Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    RaisedButton(
                      child: Text("call snacker using the global key"),
                      onPressed: () {
                        setState(() {
                          showLoader = true;
                        });
                        UserExt.getUserInfo((user) {
                          print("UUUser id = ${user.userId}");
                          _scaffoldKey.currentState.showSnackBar(new SnackBar(
                              duration: Duration(seconds: 2),
                              content: new Text(
                                  "This is you user id :${user.userId}")));

                          setState(() {
                            showLoader = false;
                          });
                        }, (error) {
                          _scaffoldKey.currentState.showSnackBar(new SnackBar(
                              duration: Duration(seconds: 2),
                              content: new Text("${error.toString()}")));

                          setState(() {
                            showLoader = false;
                          });
                        });
                      },
                    ),
                    Secondbutton(),
                  ],
                ),
              ),
              Visibility(
                child: CircularProgressIndicator(
                  backgroundColor: Colors.pink,
                ),
                visible: showLoader,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class Secondbutton extends StatefulWidget {
  @override
  _SecondbuttonState createState() => _SecondbuttonState();
}

class _SecondbuttonState extends State<Secondbutton> {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text("calling snacker without using the global key"),
      onPressed: () {
        UserExt.getUserInfo((user) {
          print("UUUser id = ${user.userId}");
          Scaffold.of(context).showSnackBar(SnackBar(
            backgroundColor: Colors.redAccent,
            content: Text("This is you user id ${user.userId}"),
          ));
        }, (error) {
          Scaffold.of(context).showSnackBar(SnackBar(
            duration: Duration(seconds: 2),
            backgroundColor: Colors.redAccent,
            content: Text("${error.toString()}"),
          ));
        });
      },
    );
  }
}


Ваша проблема была в том, что он не получил правильный контекст.

2 голосов
/ 06 марта 2020

Из официальной документации флаттера https://api.flutter.dev/flutter/material/Scaffold/of.html

Когда Scaffold фактически создается в той же функции сборки, аргумент контекста для функции сборки не может быть используется для поиска скаффолда (поскольку он «над» виджетом, возвращаемым в дереве виджетов). В таких случаях для создания новой области видимости с BuildContext, который находится «под» скаффолдом, можно использовать следующую технику с помощью Builder: Scaffold , поэтому вместо использования контекста Direct parent, который создает экземпляр Scaffold, используйте контекст дочернего элемента.

Ниже будет работать код.

class _ApiCallingState extends State<ApiCalling> {
  bool showLoader = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Builder(
        builder: (context)=>
            Center(
        child: Stack(
          children: <Widget>[
            Center(
              child: RaisedButton(
                child: Text("Call API"),
                onPressed: () {
                  setState(() {
                    showLoader = true;
                  });
                  UserExt.getUserInfo((user) {
                    print("UUUser id = ${user.userId}");
                    print("context==$context");
                    Scaffold.of(context).showSnackBar(SnackBar(
                      content: Text(" User Id${user.userId}"),
                    ));
                     setState(() {
                      showLoader = false;

                    });



                  }, (error) {
                    setState(() {
                      showLoader = false;
                    });
                    Scaffold.of(context).showSnackBar(SnackBar(
                      content: Text("${error}"),
                    ));

                  });
                },
              ),
            ),
            Visibility(
              child:
              Center(
                child:CircularProgressIndicator(
                  backgroundColor: Colors.pink,
                ),

              ),
              visible: showLoader,
            )
          ],
        ),
      ),
      )

    );
  }
}
0 голосов
/ 05 марта 2020

объявить глобальный ключ final _scaffoldKey = GlobalKey ();

и в пользовательском интерфейсе _scaffoldKey.currentState.showSnackBar (snackbar);

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