Flutter 基于getX搭建通用项目架构

计算机软件开发 2024-9-28 04:25:47 97 0 来自 中国
从事flutter开辟工作两年多了,做了几个项目,从刚开始的Provider到如今的GetX,Bloc都在项目中利用过,本篇文章连合GetX特性和项目中的现实运用整理了一套基于GetX搭建通用项目架构,代码会上传gitee.特此分享,欢迎探究交换。

老例子,先上结果。

3.gif 4.gif 5.gif 一. 网络封装

网络告急利用的是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类操持


  • BaseView 操持
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中可以方便设置和获取一些常用的页面属性以及完成页面根本布局。


  • BaseController 操持
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%都是如许)的都要把这些判断复制一遍,非常贫苦,那么重点来了:


  • BaseCommonView 操持
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。方便网络哀求的方法和一些参数调用。
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-12-4 16:46, Processed in 0.162947 second(s), 36 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表