Flutter跨页面共享Cubit时遭遇ProviderNotFoundException错误求助
BlocProviderNotFoundException 问题解决
问题描述
在Chapters页面通过BlocProvider创建MangaScreenCubit后,尝试在Description页面直接复用该Cubit实例,触发了ProviderNotFoundException错误。
Chapters页面代码
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:manga_series/modules/manga/arabic_chapters.dart'; import 'package:manga_series/modules/manga/cubit/cubit.dart'; import 'package:manga_series/modules/manga/cubit/states.dart'; import 'package:manga_series/modules/manga/english_chapters.dart'; import 'package:manga_series/shared/style/colors.dart'; class Chapters extends StatelessWidget { const Chapters({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocProvider( create: (BuildContext context) => MangaScreenCubit(), child: BlocConsumer<MangaScreenCubit, MangaScreenStates>( listener: (context, state) => {}, builder: (context, state) { var cubit = MangaScreenCubit.get(context); return DefaultTabController( initialIndex: cubit.chaptersLanguage, length: 2, child: SingleChildScrollView( physics: BouncingScrollPhysics(), scrollDirection: Axis.vertical, child: Column( mainAxisSize: MainAxisSize.min, children: [ Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: Row( children: [ Expanded( child: Text( "Chapters Number : 54", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500), ), ), TextButton( onPressed: () { cubit.changeChaptersLanguageEnglish(); }, child: Text( "English", style: TextStyle( fontSize: 12, color: cubit.chaptersLanguage == 0 ? primaryColor : Colors.grey), )), TextButton( onPressed: () { cubit.changeChaptersLanguageArabic(); }, child: Text( "Arabic", style: TextStyle( fontSize: 12, color: cubit.chaptersLanguage == 1 ? primaryColor : Colors.grey), )), ], ), ), IndexedStack( children: <Widget>[ Visibility( child: EnglishChapters(), maintainState: true, visible: cubit.chaptersLanguage == 0, ), Visibility( child: ArabicChapters(), maintainState: true, visible: cubit.chaptersLanguage == 1, ), ], index: cubit.chaptersLanguage, ), ], ), ), ); }, ), ); } }
错误信息
_InheritedProviderScope<T?>>() as _InheritedProviderScopeElement<T?>?; if (inheritedElement == null && null is! T) { throw ProviderNotFoundException(T, context.widget.runtimeType); } return inheritedElement; }
Description页面代码
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:manga_series/modules/manga/cubit/cubit.dart'; import 'package:manga_series/modules/manga/cubit/states.dart'; import 'package:manga_series/shared/components/components.dart'; import 'package:readmore/readmore.dart'; class Descreption extends StatelessWidget { Descreption({Key? key}) : super(key: key); String descreption = "Lorem ipsum dolor sit amet, ea sed quis utinam invidunt, nec no tantas aeterno, at quot insolens mea. Dicta menandri per te, vim ad summo antiopam imperdiet, eu nostro repudiare cum. Ex aliquando eloquentiam quo, at mea quem phaedrum convenire. Eu vel legendos assentior repudiandae, vix te case accumsan suscipit.Tale etiam indoctum vel ei. Cu nam velit altera delectus. Graeci detraxit vix ad, an pri solum summo vivendo. Eu liber dolore intellegebat vis. Vis facilis suavitate instructior ut, et ullum periculis hendrerit vim. Te sonet albucius legendos mel, simul labores an vel.Lorem ipsum dolor sit amet, ea sed quis utinam invidunt, nec no tantas aeterno, at quot insolens mea. Dicta menandri per te, vim ad summo antiopam imperdiet, eu nostro repudiare cum. Ex aliquando eloquentiam quo, at mea quem phaedrum convenire. Eu vel legendos assentior repudiandae, vix te case accumsan suscipit.Tale etiam indoctum vel ei. Cu nam velit altera delectus. Graeci detraxit vix ad, an pri solum summo vivendo. Eu liber dolore intellegebat vis. Vis facilis suavitate instructior ut, et ullum periculis hendrerit vim. Te sonet albucius legendos mel, simul labores an vel.Lorem ipsum dolor sit amet, ea sed quis utinam invidunt, nec no tantas aeterno, at quot insolens mea. Dicta menandri per te, vim ad summo antiopam imperdiet, eu nostro repudiare cum. Ex aliquando eloquentiam quo, at mea quem phaedrum convenire. Eu vel legendos assentior repudiandae, vix te case accumsan suscipit.Tale etiam indoctum vel ei. Cu nam velit altera delectus. Graeci detraxit vix ad, an pri solum summo vivendo. Eu liber dolore intellegebat vis. Vis facilis suavitate instructior ut, et ullum periculis hendrerit vim. Te sonet albucius legendos mel, simul labores an vel.Lorem ipsum dolor sit amet, ea sed quis utinam invidunt, nec no tantas aeterno, at quot insolens mea. Dicta menandri per te, vim ad summo antiopam imperdiet, eu nostro repudiare cum. Ex aliquando eloquentiam quo, at mea quem phaedrum convenire. Eu vel legendos assentior repudiandae, vix te case accumsan suscipit.Tale etiam indoctum vel ei. Cu nam velit altera delectus. Graeci detraxit vix ad, an pri solum summo vivendo. Eu liber dolore intellegebat vis. Vis facilis suavitate instructior ut, et ullum periculis hendrerit vim. Te sonet albucius legendos mel, simul labores an vel."; @override Widget build(BuildContext context) { return BlocConsumer<MangaScreenCubit, MangaScreenStates>( listener: (context, state) => {}, builder: (context, state) { return Padding( padding: const EdgeInsets.symmetric( horizontal: 15, ), child: SingleChildScrollView( scrollDirection: Axis.vertical, physics: const BouncingScrollPhysics(), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox( height: 10, ), const Text( "The Beginning After The End", textWidthBasis: TextWidthBasis.longestLine, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 22, fontWeight: FontWeight.w600), ), const SizedBox( height: 8, ), Row( children: [ Row( children: const [ Icon( Icons.fireplace_outlined, color: Colors.grey, size: 20, ), SizedBox( width: 5, ), Text( "154.3K", style: TextStyle( fontSize: 13, color: Colors.grey, ), ), ], ), const SizedBox( width: 15, ), Row( children: const [ Icon( Icons.remove_red_eye_outlined, size: 20, color: Colors.grey, ), SizedBox( width: 5, ), Text( "257.9K", style: TextStyle( fontSize: 13, color: Colors.grey, ), ), ], ), const SizedBox( width: 15, ), Row( children: const [ Icon( Icons.star, size: 20, color: Colors.orangeAccent, ), Text( "4", style: TextStyle( fontSize: 13, color: Colors.grey, ), ), ], ), ], ), const SizedBox( height: 15, ), Row( children: [ mangaInfo(text: "Completed"), const SizedBox(width: 5), mangaInfo(text: "English"), const SizedBox(width: 5), mangaInfo(text: "Arabic"), ], ), const SizedBox( height: 20, ), const Text( "Update On Monday", style: TextStyle( color: Colors.black87, fontSize: 14, fontWeight: FontWeight.bold), ), const SizedBox( height: 5, ), ReadMoreText( descreption, trimLines: 4, trimMode: TrimMode.Line, moreStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Color.fromARGB(255, 6, 193, 71), ), lessStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Color.fromARGB(255, 6, 193, 71), ), ), const SizedBox( height: 15, ), SingleChildScrollView( scrollDirection: Axis.horizontal, physics: const BouncingScrollPhysics(), child: Row( children: [ mangaInfo(text: "Action"), const SizedBox(width: 5), mangaInfo(text: "Adventure"), const SizedBox(width: 5), mangaInfo(text: "Fantasy"), const SizedBox(width: 5), mangaInfo(text: "Magic"), const SizedBox(width: 5), mangaInfo(text: "Shounen"), ], ), ), const SizedBox( height: 30, ), secondaryButton( text: "My List", width: 50.0, icon: Icons.add, onPressed: () {}, ), ], ), ), ); }, ); } } Widget createButton({icon, color, text}) { return ButtonTheme( minWidth: 140, height: 45, child: FlatButton.icon( onPressed: () {}, icon: icon, label: Text( text, style: const TextStyle(color: Colors.white), ), color: color, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), ), ); } Widget mangaInfo({required String text}) { return Container( height: 25, width: 85, decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), color: Colors.grey[300]), child: Center( child: Text(text, style: TextStyle( fontSize: 12, color: Colors.grey[700], fontWeight: FontWeight.bold))), ); }
问题原因
BlocProvider的作用域仅限于其包裹的子Widget树。你在Chapters页面内创建的MangaScreenCubit,只能被Chapters的子组件访问,而Description页面不在这个子树中,因此会抛出找不到Provider的错误。
解决方案
方案1:提升BlocProvider到共同父组件
将BlocProvider移到Chapters和Description页面的共同父组件中,比如包含这两个页面的TabBarView、PageView,或者路由栈的上层页面。这样两个页面都能共享同一个Cubit实例。
示例:
假设父页面是MangaDetailPage,包含Description和Chapters两个子页面:
class MangaDetailPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( create: (context) => MangaScreenCubit(), child: DefaultTabController( length: 2, child: Scaffold( appBar: TabBar(tabs: [Tab(text: "Description"), Tab(text: "Chapters")]), body: TabBarView( children: [Descreption(), Chapters()], ), ), ), ); } }
方案2:通过路由跳转时传递Cubit实例
如果Description页面是通过路由从Chapters页面跳转过去的,使用BlocProvider.value包裹Description页面,传递已有的Cubit实例:
在Chapters页面中跳转的代码:
// 获取当前Cubit实例 var cubit = MangaScreenCubit.get(context); // 跳转到Description页面 Navigator.push( context, MaterialPageRoute( builder: (context) => BlocProvider.value( value: cubit, child: Descreption(), ), ), );
这样Description页面就能访问到同一个Cubit实例,不会重新创建,也不会触发ProviderNotFoundException。
内容的提问来源于stack exchange,提问作者anikki00
相关产品推荐
相关产品推荐

