flutter 要从“initState()”异步初始化的提供程序,但get“找不到正确的提供程序”

kb5ga3dv  于 2023-01-27  发布在  Flutter
关注(0)|答案(1)|浏览(134)

我开发了一个广告应用程序,在详细视图上有一个消息按钮。
当用户点击它时,chats视图(有状态小部件)被推到屏幕上。
initState()用于调用asyncInitMessages()asyncInitMessages()从远程数据库异步获取聊天和相关消息,asyncInitMessages()属于Chats类,Chats类扩展了ChangeNotifier

/// A chat conversation
class Chats extends ChangeNotifier {
  /// Internal, private state of the chat.

  void asyncInitMessages(
      {required ClassifiedAd ad,
      required String watchingUserId,
      required bool isOwner}) async {

     // blah blah
  }
}

ClassifiedAdMessagesView有状态小部件类实现如下(代码片段):

@override
  void initState() {
    
    // == Fetch conversation and messages 
    asyncInitMessages();

  }

void asyncInitMessages() async {
    // === Update all messages
    try {
      Provider.of<Chats>(context, listen: false).asyncInitMessages(
          ad: widget.ad,
          watchingUserId: widget.watchingUser!.uid,
          isOwner: _isOwner);
    } catch (e) {
      if (mounted) {
        setState(() {
          _error = "$e";
          _ready = true;
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    // <<<<<<<<<<< The exception fires at the Consumer line right below
    return Consumer<Chats>(builder: (context, chats, child) {
      return Scaffold(
        // ... blah blah

最后,当运行ll时,我在构建中的Consumer行得到了异常:
找不到正确的提供程序
帮助非常感谢。
[更新]
这里是主要的(非常远离消息屏幕)

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  //if (Firebase.apps.isEmpty) {
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  // } else {
  //   Firebase.app(); // if already initialized, use that one
  // }
  if (USE_DATABASE_EMULATOR) {
    FirebaseDatabase.instance.useDatabaseEmulator(emulatorHost, emulatorPort);
  }

  runApp(RootRestorationScope(
      restorationId: 'root',
      child: ChangeNotifierProvider(
          create: (context) => StateModel(),
          child: const App())));
}

class App extends StatefulWidget {
  const App({super.key});
  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> {

  @override
  Widget build(BuildContext context) {
    return PersistedAppState(
        storage: const JsonFileStorage(),
        child: MultiProvider(
            providers: [
              ChangeNotifierProvider<ThemeModel>.value(value: _themeModel),
              //ChangeNotifierProvider<AuthModel>.value(value: _auth),
            ],
            child: Consumer<ThemeModel>(
                builder: (context, themeModel, child) => MaterialApp(
                  // blah blah

    }
  }
}

而组件就在

/// Classified ad detail view
class ClassifiedAdDetailView extends StatefulWidget {
  final User? watchingUser;
  final ClassifiedAd ad;

  const ClassifiedAdDetailView(
      {Key? key, required this.watchingUser, required this.ad})
      : super(key: key);

  @override
  State<ClassifiedAdDetailView> createState() => _ClassifiedAdDetailViewState();
}

class _ClassifiedAdDetailViewState extends State<ClassifiedAdDetailView>
    with TickerProviderStateMixin {

 @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
        create: (context) => Chats(),
        builder: ((context, child) => Scaffold(

// blah blah

          ElevatedButton(
            onPressed: () => Navigator.of(context).push(MaterialPageRoute(
                                builder: (context) => ClassifiedAdMessagesView(
                                    ad: ad,
                                    watchingUser: widget.watchingUser)));
                          }),
djmepvbi

djmepvbi1#

提供商必须位于您希望使用ConsumerProvider.of的小部件上方的小部件树中。当您使用Navigator推送新路由时,它不会将推送的路由添加到您推送的小部件下方,而是将其添加到homeMaterialApp所在的同一级别。
(我认为您收到的错误消息还指出您无法在路由之间访问提供商。)
一般来说,如果你推送一些航线,树形图会是这样的(用Flutter Widget Inspector检查):

  • 材料应用程序
  • 小部件1
  • 小部件2
  • 小工具21
  • 小工具22
  • 第1页
  • 小部件1
  • 小部件2
  • 第二页
  • 第3页

在代码中,您在ClassifiedAdDetailView中创建提供程序,然后推送
onPressed方法中的ClassifiedAdMessagesView。您将无法从ClassifiedAdMessagesView访问此提供程序,因为树将类似(简化):

  • 材料应用程序
  • 分类广告详细信息视图
  • 分类广告消息视图

解决方案是“提升状态”,将提供者放在你需要访问的每个小部件之上,它可以是你现有Multiprovider的一部分,在MaterialApp之上,但是如果太远,你需要找到一个合适的位置,在ClassifiedAdDetailViewClassifiedAdMessagesView之上。

相关问题