Flutter是谷歌出品,自然是天然适配MVVM架构,对于日常业务开发,使用该架构,可以很好地完成逻辑剥离,下面将实现一个demo讲解flutter中MVVM的实践。
一、跨组件状态管理框架:Provider
参考资料:https://book.flutterchina.club/chapter7/provider.html
二、架构模式图:
三、代码实现
- ViewModel层:ListDataViewModel.dart
import 'package:flutter/cupertino.dart'; import '../model/QueryListDataModel.dart'; /** * 需要继承ChangeNotifier */ class ListDataViewModel extends ChangeNotifier { ListDataViewModel(this.keyword); final String keyword; QueryListDataModel queryListDataModel; List<dynamic> listData = []; void getListDataFromNetwork() { //延时三秒返回结果,模拟网络请求 Future.delayed(Duration(seconds: 3), () { queryListDataModel = QueryListDataModel(); if (keyword.isNotEmpty) { listData.addAll(queryListDataModel.list); notifyListeners(); //通知监听者,必须要调用 } }); } }
- Model层:QueryListDataModel.dart
class QueryListDataModel { List<String> list = [ '测试数据1', '测试数据2', '测试数据3', '测试数据4', '测试数据5', '测试数据6', '测试数据7', '测试数据8', '测试数据9', '测试数据10', '测试数据11', '测试数据12', '测试数据13', '测试数据14', '测试数据15', ]; }
- View层:ListPage.dart
import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:my_app/viewmodel/ListDataHeadViewModel.dart'; import 'package:my_app/viewmodel/ListDataViewModel.dart'; import 'package:provider/provider.dart'; class ListPage extends StatelessWidget { @override Widget build(BuildContext context) { /** * 使用ChangeNotifierProvider或者MutiProvider将需要共享数据的widget包起来, * 单个NotifierProvider使用ChangeNotifierProvider, * 多个NotifierProvider使用MutiProvider */ return MultiProvider(providers: [ ChangeNotifierProvider( create: (context) => ListDataViewModel('shanghai')), ChangeNotifierProvider( create: (context) => ListDataHeadViewModel()) ], child: ListPageful(), ); } } class ListPageful extends StatefulWidget { @override _ListPagefulState createState() => _ListPagefulState(); } class _ListPagefulState extends State<ListPageful> { @override Widget build(BuildContext context) { /** * 可以在被包起来widget中的任一子widget中获取ViewModel, * 可以在在StatefulWidget中的build方法中获取, * 也可以使用Builder组件进行获取; */ var listDataVM = Provider.of<ListDataViewModel>(context); return MediaQuery( data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0), child: ListPageImpl(listDataVM)); } } class ListPageImpl extends StatefulWidget { ListDataViewModel listDataModel; ListPageImpl(this.listDataModel); @override _ListPageImplState createState() => _ListPageImplState(); } class _ListPageImplState extends State<ListPageImpl> { ListDataViewModel listDataViewModel; List<dynamic> datas = []; @override void initState() { super.initState(); /** * 在子widget中获取ViewModel,使用ViewModel获取数据,并对ViewModel添加监听,设置数据刷新界面; * (注:有两种方式刷新界面,<1>.监听数据,更改state的值刷新界面。<2>.直接在widget中使用ViewModel中的数据。具体根据业务需求;) */ listDataViewModel = widget.listDataModel; listDataViewModel.getListDataFromNetwork(); listDataViewModel.addListener(() { if (mounted) { this.setState(() { datas = listDataViewModel.listData; }); } }); } @override void dispose() { /** * 在界面销毁时移除对ViewModel的监听 */ listDataViewModel.removeListener(() {}); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('MVVM Demo'), ), body: ListView.builder( padding: EdgeInsets.all(16.0), itemCount: datas.length, itemBuilder: (context, i) { if (i.isOdd) { return Divider(); } return _buildRow(datas.length != 0? datas?.elementAt(i):""); }), ); } Widget _buildRow(dynamic model) { return ListTile( title: Text( model, style: TextStyle(fontSize: 24.0, color: Color(0xFFFC6E51)), ), ); } }
相关说明已经在代码注释中体现。
demo源码已上传github:https://github.com/hanren726/FlutterMVVM_Demo,欢迎star和folk~