Flutter 上下文对 null 值使用 Null 检查运算符

问题描述 投票:0回答:3

我希望获得有关如何避免某些用户出现此问题的指导。这不是一般性错误。 似乎 flutter 在我的应用程序的初始化流程中禁用/处置上下文。 我在 initState 中使用 FutureBuilder。 仅在 future 方法完成调用多个例程后才会加载屏幕。 我在 initiState 中初始化我的 Provider,如下所示:

` @override void initState() {       
super.initState();     
WidgetsBinding.instance.addObserver(this);      
_userDataController = Provider.of<UserDataController>(context, listen: false);        
futureResult = getDataIni();     
}`

在我的 getDataIni 方法中,我初始化远程配置设置、通知等,并从我的提供程序调用方法。在某些设备中,调用提供程序方法时会出现此错误:

await _userDataController.loadData(context);

错误: 对空值使用空检查运算符 #0 State.context (package:flutter/src/widgets/framework.dart:954)#1 _HomePageState.getDataIni.....)#2 _FutureBuilderState._subscribe. (包:flutter/src/widgets/async.dart:628)

我知道这是一个颤振错误,而不是提供者。但如何避免这种情况并保证整个应用程序的状态呢? 我的小部件是一个 stateFullWidget。

我希望上下文始终可用。正如我所说,这个错误并不普遍。

更新 不幸的是问题没有解决,我不知道还能做什么。 如果有人可以帮助我。

出现在队列中:

await _userDataController.loadSync(context, signatureController: _signatureController);

错误: 对空值使用空检查运算符

#0 State.context (package:flutter/src/widgets/framework.dart:958)#1
_HomePageState.getData (package:appxxxx/pages/home_page.dart:211)<asynchronous suspend>#2
_FutureBuilderState._subscribe.<anonymous close> (package:flutter/src/widgets/async.dart:624)<asynchronous suspend>

后续加载的方法完整代码:

Future<bool> getData() async {
    try {
      _abaController = context.read<AbaController>();
      _assinaturaController = context.read<AssinaturaController>();
      var _userDataController = context.read<UserDataController>();
      isOnline = await Conexao.isOnline();

      //test your internet connection online
      if (isOnline == false)
        return Future<bool>.value(false);

      //get current date and time from server
      await DataUtils.loadDateTimeServer();
      //initialize remote config
      await GetIt.I<RemoteConfigService>().loadData();
      ///Checks if app update is mandatory and aborts
      int versaoAppLocal = int.parse((await PackageInfo.fromPlatform()).buildNumber);
      int versaoAppRemoteConfig = GetIt.I<RemoteConfigService>().versaoMinimaApp;

      if (versaoAppLocal < versaoAppRemoteConfig){
        atualizacaoAppObrigatoria = true;
        return Future<bool>.value(false);
      }

      ///Check if the environment is under maintenance and abort
      if (GetIt.I<RemoteConfigService>().isAmbienteEmManutencao){
        isAmbienteEmManutencao = true;
        return Future<bool>.value(false);
      }

      //retrieves instance Firebase auth and sets user logged in provider
      await GetIt.I<AuthService>().init(context);
      //initializes the subscriptions plugin (revenuecat) and sets if the user is a subscriber or not
      await GetIt.I<PurchaseService>().load(context);
      //initialize notifications plugin settings
      await _initializeNotificationsSetttings();
      //call service to load a list of session data
      await TickersHelper.load();
      await _userDataController.loadSync(context, assinaturaController: _assinaturaController);
      _requestPermissions();
      _configureDidReceiveLocalNotificationSubject();
      _configureSelectNotificationSubject();
      _loadAndSetTabIcons();
      await GetIt.I<UsuarioApiService>().callIncluirTokenPush();
      await GetIt.I<NotificacoesHelper>().programaNotifications(context);


      await _showDialogUmpCMP();
      await _autenticaBiometria();
      await _initDynamicLinks();

    } catch (ex, stack) {
       ....
    }
flutter dart provider
3个回答
0
投票

但是应用程序不能多次调用 getDataIni()。是什么导致 didChangeDependency 运行? getDataIni 只能在屏幕打开时运行一次。


0
投票

编辑:

为了更好的解释,我添加了一个小代码片段:

class YourPage extends StatefulWidget {
  const YourPage({super.key});

  @override
  State<YourPage> createState() => _YourPageState();
}

class _YourPageState extends State<YourPage> {
  late Future<int> future;
  late Future<int> future2;

  Future<int> _someAsyncChain() async {
    await Future<void>.delayed(const Duration(seconds: 3));
    return Provider.of<int>(context, listen: false); // provider simulation
  }

  @override
  void initState() {
    future = _someAsyncChain();
    future2 = _someAsyncChain(); // throws the exception
  }

  @override
  void dispose() {
    print("disposed");
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<int>(
      future: future,
      builder: (BuildContext context, AsyncSnapshot<int> data) {
        if (data.hasData) {
          return Text("DATA: ${data.data}");
        }
        return const Text("no data :(");
      },
    );
  }
}

Widget _build(BuildContext context) {
  bool showFirst = false;
  return StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
    return Column(
      children: [
        showFirst ? Provider<int>(create: (_) => 100, child: YourPage()) : Text("second page"),
        ElevatedButton(onPressed: () => setState(() => showFirst = !showFirst), child: Text("change")),
      ],
    );
  });
}

我猜想,如果您以某种方式比加载数据未来完成的速度更快地处理 State 对象,就会发生类似的情况。

正如您在此示例中所看到的,如果您足够快地使用

change
按钮,则会引发相同的异常,因为状态不再可用。但如果你等3秒再按下,那就一切都好了。

但是如果不知道你的整个小部件结构和你的代码

getDataIni
,很难说你的错误到底在哪里。

这也是为什么一般不建议跨异步间隙使用

BuildContext

但是您正在使用

context
State
并且您的
FutureBuilder
位于您的
State
内部,对吧?因为通常未来的构建器应该能够捕获这样的错误(这也是为什么在上面的示例中,
future
不会抛出异常,只有
future2
会抛出异常)。

您使用的是最新的flutter版本吗?


0
投票

您可以使用 didChangeDependency 生命周期方法代替 initState。在某些情况下,调用 initState 方法时上下文可能尚未完全初始化或可用,因此通过将初始化代码移至 didChangeDependencies,可以确保上下文可用并可供使用。

...
@override
void didChangeDependencies() {
  super.didChangeDependencies();

  _userDataController = Provider.of<UserDataController>(context, listen: false);
  futureResult = getDataIni();
}

@override
void initState() {
...

其他解决方案使用WidgetsBinding.instance.addPostFrameCallback,我已经使用此回调来执行它在构建完成时工作,我认为它也适用于您的情况。

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this);
  
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _userDataController = Provider.of<UserDataController>(context, listen: false);
    futureResult = getDataIni();
  });
}
© www.soinside.com 2019 - 2024. All rights reserved.