从事flutter开辟工作两年多了,做了几个项目,从刚开始的Provider到如今的GetX,Bloc都在项目中利用过,本篇文章连合GetX特性和项目中的现实运用整理了一套基于GetX搭建通用项目架构,代码会上传gitee.特此分享,欢迎探究交换。
老例子,先上结果。
一. 网络封装
网络告急利用的是dio 和 retrofit来实现的,关于dio的封装,思绪根本上和网上的教程大同小异.大抵思绪就是创建options对象,设置超时时间,域名,responseType,超时时间等等.然后在创建dio单例对象,给dio对象添加拦截器,我根本上添加三个拦截器分别为
* MiddleInterceptor (获取哀求路径,哀求参数,打印日志)
* ErrorInterceptor (获取错误原因,打印日志)
* ApiResultInterceptor(获取后端返回结果,处理处罚逻辑,数据返回,好比多装备登录同一账号非常处理处罚等等)
在这里代码就不贴出来了,有爱好的可以下载demo查看.
为什么要利用retrofit?
retrofit是一个非常好用强盛的代码天生器,支持POST GET PATCH PUT等哀求.界说好哀求方法,返回类型实行一行下令就会自动天生代码,在Controller中直接利用自己利用好的model即可.
常用下令:
* flutter packages pub run build_runner build
* flutter pub run build_runner build --delete-conflicting-outputs
代码界说如下所示
/// 列表接口 @GET("searchV5") Future<Result<InfoWorkModel>> getInfoListData( @Query('pn') int page, @Query('ps') int pageSize, @Query('q') String name, @Query('t') String t, ); /// 详情接口 @GET("pc/items/info") Future<Result<InfoWorkModel>> getInfoDetailData( @Query('entityId') int entityId, ); /// 点赞接口 @POST("thumbsUpOrDown") Future<Result<InfoWorkModel>> likeThumbsUpOrDown( @Body() Map<String, String> param);Result 类内里就是返回的最外层数据包罗 code,msg,data此中data是一个 泛型T可以继承任何类型,然后再界说data内里对象,也就是InfoWorkModel,如许层层界说保障每个对象都转化成modle即可.
yaml如下代码所示:
dependencies: retrofit: '>=4.0.0 <5.0.0' dio: ^4.0.6dev_dependencies: retrofit_generator: '>=5.0.0 <6.0.0' build_runner: '>=2.3.0 <4.0.0' json_serializable: ^4.4.0二. 路由操持
将至心话利用了GetX之后根本就不必要路由操持了,GetX都封装好了,在这里就说几个Api吧.
1.跳转界面
Get.toNamed('/test');
2.跳转界面传值
Get.toNamed('/test', arguments: {'id': '0'});
3.跳转界面并实行页面返回变乱(好比革新数据)
Get.toNamed("/test",)?.then((value) { print('实行变乱'); });
4.返回上一界面
Get.back();
5.返回上一界面并回调传值
Get.back(result: { 'id':1 });
6.返回上一界面并关闭当前页面
Get.offNamed("/test");
7.返回上一界面并关闭之前全部页面
Get.offAll("/test");
8.返回指定页面
Get.until((route) => Get.currentRoute == '/test');
三.状态管理
1.利用GetBuilder:
在buildContent中直接返回GetBuilder,然后在Controller中数据发生厘革后调用update()方法整个页面都会发生厘革,恰当列表页面的开辟。
GetBuilder<HomeController>( builder: (_) { return Container(); }, );2.利用RxX..和Obx()共同利用举行小部件的状态革新。
关于状态管理的操持原理:参考这篇文章
四.Base类操持
import 'package:flutter/material.dart';import 'package:flutter_screenutil/flutter_screenutil.dart';import 'package:get/get_state_manager/get_state_manager.dart';abstract class BaseView<T> extends GetView<T> { BaseView({Key? key}) : super(key: key); /// 状态栏高度 double statusBarH = ScreenUtil().statusBarHeight; /// 导航栏高度 double navBarH = AppBar().preferredSize.height; /// 安全地域高度 double safeBarH = ScreenUtil().bottomBarHeight; /// 设置配景颜色 Color? contentColor; /// 设置标题笔墨 String? navTitle; /// 设置导航栏颜色 Color? navColor; /// 设置左边按钮 Widget? leftButton; /// 设置左边宽度 double? leftWidth; /// 设置右边按钮数组 List<Widget>? rightActionList; /// 是否隐蔽导航栏 bool? isHiddenNav; /// 设置主主视图内容(子类不实现会报错) Widget buildContent(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: contentColor ?? Colors.white, appBar: isHiddenNav == true ? null : AppBar( backgroundColor: navColor ?? Colors.white70, title: Text( navTitle ?? '', ), leading: leftButton ?? const SizedBox(), leadingWidth: leftWidth ?? 0, actions: rightActionList ?? [], ), body: buildContent()); }}新创建的widget都继承自BaseView 如许在集成于BaseView 的widget中可以方便设置和获取一些常用的页面属性以及完成页面根本布局。
import 'package:flutter/material.dart';import 'package:get/get.dart';import 'package:pull_to_refresh/pull_to_refresh.dart';enum NetState { /// 初始状态 initializeState, /// 加载状态 loadingState, /// 错误状态,表现失败界面 errorState, /// 错误状态,只弹错误信息 erroronlyTotal, /// 错误状态,表现革新按钮 errorshowRelesh, /// 没有更多数据 noMoreDataState, /// 是否尚有更多数据 hasMoreDataState, /// 空数据状态 emptyDataState, /// 数据获取乐成状态 dataSussessState,}abstract class BaseController extends SuperController { /// 界说网络状态方便子控制器利用 NetState netState = NetState.initializeState; @override void onReady() { super.onReady(); initData(); } @override void onDetached() { debugPrint("a11111"); } @override void onInit() { // TODO: implement onInit super.onInit(); } @override void onInactive() { debugPrint("a11112"); } @override void onPaused() { //彻底脱离回调 debugPrint("a11113"); } @override void onResumed() { //彻底规复回调 debugPrint("a11114"); } void initData();}这个类不必要多说就是重写了一下Getx的生命周期方法,以及添加了一个网络状态的属性,为什么把网络状态加在BaseController中呢?稍后再讲。
分析:正常来说到了这一步就可以利用这两个base来做项目了,无非就是在Controller内里哀求数据,然后根据接口的返回在Controller内里更新netState网络状态,然后在widget内里根据netState的状态,判断返回LoadingWidget,大概EmptyWidget,大概ErrorWidget,数据哀求乐成返回SussessWidget,总之必要在widget内里写大量的判断逻辑,而且凡是涉及到根据网络哀求接口返返来展示页面(现实上90%都是如许)的都要把这些判断复制一遍,非常贫苦,那么重点来了:
import 'package:flutter/material.dart';import 'package:flutter_screenutil/flutter_screenutil.dart';import 'package:get_demo/base/base_view.dart';import 'package:get_demo/widget/loading_widget.dart';import '../widget/empty_status.dart';import 'base_common_controller.dart';import 'base_controller.dart';abstract class BaseCommonView<T> extends BaseView<T> { BaseCommonView({Key? key}) : super(key: key); /// 创建空视图 (子视图实现的话 Widget就是子视图实现的) Widget creatEmptyWidget() { return const EmptyStatusWidget( emptyType: EmptyStatusType.noMessage, ); } /// 创建错误视图 (子视图实现的话 Widget就是子视图实现的) Widget creatFailWidget(BaseCommonController controller) { return EmptyStatusWidget( emptyType: EmptyStatusType.fail, refreshTitle: '重新加载', width: 1.sw, height: 1.sh, onTap: () { /// 重新哀求数据 controller.getnetworkdata(controller.configNetWorkParmas()); }, ); } /// 创建页面主视图 Widget creatCommonView(BaseCommonController controller, Widget commonView) { return _refresherListView(controller, commonView); } Widget _refresherListView( BaseCommonController controller, Widget commonView) { if (controller.netState == NetState.loadingState) { /// loading 不会有这个状态,只是写一个如许的判断吧(控制器内里已经封装好了单例了,防止在网络层直接利用控制不了loading的场景) return const LoadingWidget(); } else if (controller.netState == NetState.emptyDataState) { /// 返回站位视图 return creatEmptyWidget(); } else if (controller.netState == NetState.errorshowRelesh) { /// 返回站位革新视图 return creatFailWidget(controller); } else if (controller.netState == NetState.dataSussessState) { return commonView; } else if (controller.netState == NetState.initializeState) { return const SizedBox(); } else { return const Center(child: Text('未知情况,待排查')); } }}继承自BaseCommonView的widget(view)只必要调用creatCommonView方法,
然后将自己绑定的controller(继承BaseCommonController稍后会讲)和自己页面(view)将要实现的页面widget通报BaseCommonView就可以了,在BaseCommonView中会根据controller中的网络状态(这就是把网络状态界说在BaseController中的原因了,子类都要利用不必要每次都创建了)展示差别的widget,如许就不必要在每个页面中举行重复的判断了,然后如果想自界说EmptyStatusWidget那么只必要在子页面重写creatEmptyWidget方法大概creatFailWidget方法就可以了。
- BaseCommonController 操持
和BaseCommonView配套的尚有BaseCommonController。方便网络哀求的方法和一些参数调用。
|