На этой неделе я начал разрабатывать флаттер и не могу решить эту проблему.
Я создаю страницу входа, которая вызывает API для входа и после перенаправлений на домашнюю страницу.Это исключение, сгенерированное Navigator.pushReplacement
в первом блоке кода.В этот момент apiCall.isFetching
является ложной причиной, выборка завершена, а apiCall.response
содержит необходимые данные.
Сведения об исключении:
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building Consumer<ApiCallChangeNotifier>(dirty, dependencies: [InheritedProvider<ApiCallChangeNotifier>]):
setState() or markNeedsBuild() called during build.
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: Overlay-[LabeledGlobalKey<OverlayState>#4dc85]
state: OverlayState#bd97e(tickers: tracking 1 ticker, entries: [OverlayEntry#2941b(opaque: false; maintainState: false), OverlayEntry#37814(opaque: false; maintainState: true), OverlayEntry#f92c0(opaque: false; maintainState: false), OverlayEntry#da26d(opaque: false; maintainState: true)])
The widget which was currently being built when the offending call was made was: Consumer<ApiCallChangeNotifier>
dirty
dependencies: [InheritedProvider<ApiCallChangeNotifier>]
User-created ancestor of the error-causing widget was:
Expanded file:///C:/flutter_test/lib/screens/login/LoginScreen.dart:153:37
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3687:11)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3702:6)
#2 State.setState (package:flutter/src/widgets/framework.dart:1161:14)
#3 OverlayState.insertAll (package:flutter/src/widgets/overlay.dart:346:5)
#4 OverlayRoute.install (package:flutter/src/widgets/routes.dart:43:24)
...
Вот моя функция для создания кнопки входа, она называетсяот build функция LoginScreen (StatelessWidget)
Widget loginButton(BuildContext context) {
return Consumer<ApiCallChangeNotifier>(
builder: (context, apiCall, child) => apiCall.isFetching
? CircularProgressIndicator()
: apiCall.response != null
? Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomeScreen(
(apiCall.response as LoginResponse).email)))
: RaisedButton(
...
onPressed: () {
attemptLogin(context);
},
...
));
}
Функция попытки входа:
void attemptLogin(BuildContext context) {
Provider.of<ApiCallChangeNotifier>(context, listen: false).callApi(
MyApiServices().attemptLogin,
{
'email': emailController.value.text,
'password': passwordController.value.text,
},
urlController.value.text
);
}
ApiCallChangeNotifier
class ApiCallChangeNotifier extends ChangeNotifier {
bool isFetching = false;
Object response;
Future<LoginResponse> callApi(apiFunction, bodyParams, customUrl) async {
isFetching = true;
notifyListeners();
response = await apiFunction(bodyParams, customUrl);
isFetching = false;
notifyListeners();
return response;
}
}
MyApiServices.attemptLogin
- это функция, которая обрабатывает вызов API и возвращает объект LoginResponse
Надеюсь, я предоставил достаточно информации!