> 技术文档 > Flutter MVVM+provider的基本示例

Flutter MVVM+provider的基本示例

效果图
在这里插入图片描述

provider的基本使用

暴露创建的对象

void main() { runApp( MultiProvider( providers: [ Provider(create: (context) => WordRepositoryRemote()), ChangeNotifierProvider( create: (context) => WordViewModel(context.read()), ), ], child: MyPage(), ), );}

MultiProvider声明多个provider,Provider暴露一个对象,ChangeNotifierProvider暴露一个继承ChangeNotifier的对象。
如何获取暴露的对象。

 context.watch<T>(),widget 能够监听到 T 类型的 provider 发生的改变。 context.read<T>(),直接返回 T,不会监听改变。 context.select<TR>(R cb(T value)),允许 widget 只监听 T 上的一部分内容的改变。

例子

 wordViewModel = context.read<WordViewModel>();

监听viewmodel更新ui。
当WordViewModel数据有变化并调用notifyListeners()时更新ui。

 body: Consumer<WordViewModel>( builder: (context, wordViewModel, child) { if (wordViewModel.isLoading) {//加载中  ........ } else if (wordViewModel.error != null) {//错误  ....... } else {//数据处理与显示 ......... } }, ),

MVVM

model层
模拟一个从网络获取单词数据,延迟2s。
模型

class WordModel { String random; String def; String pron; String wordAudio; String word; WordModel(this.random, this.def, this.pron, this.wordAudio, this.word);}

从网络获取

import \'package:first_flutter/model/word_model.dart\';class WordRepositoryRemote { ///模拟网络请求 Future<List<WordModel>> getWordList() async { List<WordModel> wordList = []; await Future.delayed(Duration(seconds: 2)); WordModel wordModel1 = WordModel( \"0\", \"抛弃,遗弃;中止;陷入,沉湎于\", \" əˈbændən\", \"http://dict.youdao.com/dictvoice?audio=abandon\", \"abandon\", ); WordModel wordModel2 = WordModel( \"1\", \"抛弃;放纵\", \" əˈbændənmənt\", \"http://dict.youdao.com/dictvoice?audio=abandonment\", \"abandonment\", ); WordModel wordModel3 = WordModel( \"2\", \"缩略词,缩写形式;缩略\", \" əˌbriːviˈeɪʃn\", \"http://dict.youdao.com/dictvoice?audio=abbreviation\", \"abbreviation\", ); wordList.add(wordModel1); wordList.add(wordModel2); wordList.add(wordModel3); return wordList; }}

viewmodel
创建WordViewModel类继承ChangeNotifier。

import \'package:first_flutter/model/word_repository_remote.dart\';import \'package:flutter/foundation.dart\';import \'../model/word_model.dart\';class WordViewModel extends ChangeNotifier { WordRepositoryRemote wordRepositoryRemote; List<WordModel> wordList = []; bool _isLoading = true; String? _error; WordViewModel(this.wordRepositoryRemote); bool get isLoading => _isLoading; //请求单词数据 void getWordList() async { _isLoading = true; _error = null; notifyListeners(); try { wordList = await wordRepositoryRemote.getWordList(); } catch (e) { _error = e.toString(); } finally { _isLoading = false; notifyListeners(); } } String? get error => _error;}

上面代码中notifyListeners调用后,就会调用view层的Consumer。
view

import \'package:first_flutter/model/word_repository_remote.dart\';import \'package:first_flutter/view_model/word_view_model.dart\';import \'package:flutter/material.dart\';import \'package:provider/provider.dart\';import \'model/word_model.dart\';void main() { runApp( MultiProvider( providers: [ Provider(create: (context) => WordRepositoryRemote()), ChangeNotifierProvider( create: (context) => WordViewModel(context.read()), ), ], child: MyPage(), ), );}class MyPage extends StatelessWidget { const MyPage({super.key});  Widget build(BuildContext context) { return MaterialApp(theme: ThemeData(), home: WordWidget()); }}class MyState extends State { late WordViewModel wordViewModel;  void initState() { super.initState(); wordViewModel = context.read<WordViewModel>(); Future.microtask(() { if(mounted){ wordViewModel.getWordList(); } },); }  Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(\"单词 \"), centerTitle: true), body: Consumer<WordViewModel>( builder: (context, wordViewModel, child) { if (wordViewModel.isLoading) { return Container(  color: Colors.white,  child: Center(child: CircularProgressIndicator()), ); } else if (wordViewModel.error != null) { return Center(child: Text(\'错误: ${wordViewModel.error}\')); } else { if (wordViewModel.wordList.isEmpty) {  return Center(child: Text(\"暂无数据\")); } else {  List<Widget> wlist = [];  for (int i = 0; i < wordViewModel.wordList.length; i++) { WordModel wm = wordViewModel.wordList[i]; ListTile listTile = ListTile(  title: Text(wm.word),  subtitle: Text(wm.def), ); wlist.add(listTile);  }  return ListView(children: wlist); } } }, ), ); }}class WordWidget extends StatefulWidget {  State<StatefulWidget> createState() { return MyState(); }}

Future.microtask 的作用就是将一个异步任务调度到微任务队列中,使其在当前同步代码执行结束后、事件队列中的下一个任务被执行之前得到执行。mounted 表示当前 State 对象是否仍然与一个有效的 Widget 关联。除了使用Future.microtask之外,还可以使用

 WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; wordViewModel.getWordList(); });

WidgetsBinding.instance.addPostFrameCallback调用时机,在一帧绘制完成之后、下一帧开始之前立即调用。