我开发了一个广告应用程序,在详细视图上有一个消息按钮。
当用户点击它时,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)));
}),
1条答案
按热度按时间djmepvbi1#
提供商必须位于您希望使用
Consumer
或Provider.of
的小部件上方的小部件树中。当您使用Navigator
推送新路由时,它不会将推送的路由添加到您推送的小部件下方,而是将其添加到home
或MaterialApp
所在的同一级别。(我认为您收到的错误消息还指出您无法在路由之间访问提供商。)
一般来说,如果你推送一些航线,树形图会是这样的(用Flutter Widget Inspector检查):
在代码中,您在
ClassifiedAdDetailView
中创建提供程序,然后推送onPressed
方法中的ClassifiedAdMessagesView
。您将无法从ClassifiedAdMessagesView
访问此提供程序,因为树将类似(简化):解决方案是“提升状态”,将提供者放在你需要访问的每个小部件之上,它可以是你现有
Multiprovider
的一部分,在MaterialApp
之上,但是如果太远,你需要找到一个合适的位置,在ClassifiedAdDetailView
和ClassifiedAdMessagesView
之上。