当前位置: 首页 > ops >正文

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< WordViewModel >。
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调用时机,在一帧绘制完成之后、下一帧开始之前立即调用。

http://www.xdnf.cn/news/19160.html

相关文章:

  • ceph配置集群
  • VGG改进(6):基于PyTorch的VGG16-SE网络实战
  • “我店模式“当下观察:三方逻辑未变,三大升级重构竞争力
  • 详解常见的多模态大模型指令集构建
  • vue表格底部添加合计栏,且能跟主表同时滑动
  • 「鸿蒙系统的编程基础」——探索鸿蒙开发
  • 机器视觉学习-day12-图像梯度处理及图像边缘检测
  • REST API 是无状态的吗,如何保障 API 的安全调用?
  • 中科院人机交互科研分享-田丰
  • OpenCV 轮廓分析实战:从检测到形状匹配的完整指南
  • 【后端】云服务器用nginx配置域名访问前后端分离项目
  • SpringBoot防止重复提交(2)
  • docker 部署Skywalking
  • 干掉抽取壳!FART 自动化脱壳框架与 Execute 脱壳点解析
  • OpenCV DNN 模块完全指南:从理论基础到实战应用 —— 图像分类与目标检测的深度学习实现(含 Python/C++ 代码与性能分析)
  • 一站式可视化运维:解锁时序数据库 TDengine 的正确打开方式
  • 微信小程序长按识别图片二维码
  • 【C语言】字符函数与字符串函数实战:用法原理 + 模拟实现
  • 零、2025 年软件设计师考试大纲
  • Citrix 零日漏洞自五月起遭积极利用
  • Redis-基数统计、位图、位域、流
  • LangChain.js 实战与原理:用 LCEL 构建可维护的 RAG / Agent 系统(含 4 套 30+ 行代码)
  • 大语言模型生成的“超龄劳动者权益保障制度系统化完善建议(修订版)”
  • Day17(前端:JavaScript基础阶段)
  • Elasticsearch:Semantic text 字段类型
  • PostgreSQL令牌机制解析
  • Linux从入门到进阶--第四章--Linux使用操作
  • TuringComplete游戏攻略(2.1算数运算)
  • Xshell 自动化脚本大赛技术文章大纲
  • BGP路由协议(三):路径属性