阅读 4645
基于Flutter2.0,语法空安全,Provider MVVM的最佳实践,可以用于线上应用的优秀架构

基于Flutter2.0,语法空安全,Provider MVVM的最佳实践,可以用于线上应用的优秀架构

前言

BaseFlutter开源项目基于Flutter2.0,语法上空安全,是Provider MVVM的最佳实践,可以用于线上应用的优秀架构,该项目使用了很多实际项目开发中需要用到了技术和第三方框架,而且做了很多基础封装,可以直接拿到实际项目中使用,而且学习这个项目还可以帮助新手减降低学习难度,提供学习方向,实现flutter快速入门,github链接

代码结构

image.png

image.png

部分代码示例

abstract class BaseState<W extends StatefulWidget, VM extends BaseViewModel>
    extends State<W>
    with
        BaseStateInterface,
        NavigatorMixin,
        ToastMixin,
        EventBusMixin,
        SharePreferenceMixin,
        ScreenAdapterMixin{
  late VM viewModel;//这里需要改成late,不能用?,不然Provider会报错
  EventBus? eventBus;
  LoadingDialog? loadingDialog;

  late bool isBuildFinish;

  @override
  void initState() {
    super.initState();
    isBuildFinish = false;
    WidgetsBinding widgetsBinding = WidgetsBinding.instance!;
    widgetsBinding.addPostFrameCallback((callback) {
      //说明build结束了
      print("====>build结束了");
      isBuildFinish = true;
      onBuildFinish();
    });

    setContext(context);
    setIsDispose(false);
    viewModel = getIt.get<VM>();
    viewModel.context = context;
    viewModel.init();
    viewModel.showLoadingFun = () {
      showLoading();
    };
    viewModel.dismissLoadingFun = () {
      loadingDialog?.dismissDialog();
    };
    initEventBus();
  }

  @override
  void onBuildFinish() {}

  @override
  void initEventBus() {
    if (eventBus == null) {
      eventBus = EventBus.get();
    }
  }

  void showLoading() async {
    if (isBuildFinish) {
      //必须等到父组件build结束后才能构建自己,https://blog.csdn.net/qq_39493848/article/details/108514136
      showDialog(
          context: context,
          builder: (_) {
            if (loadingDialog == null) {
              loadingDialog = LoadingDialog();
            }
            return loadingDialog!;
          });
    } else {
      await Future.delayed(Duration(milliseconds: 10));
      showLoading();
    }
  }

  @override
  void dispose() {
    super.dispose();
    setIsDispose(true);
    viewModel.showLoadingFun = null;
    viewModel.dismissLoadingFun = null;
  }
}

复制代码
abstract class BaseViewModel<M extends Object> extends ChangeNotifier
    with
        BaseViewModelInterface,
        NavigatorMixin,
        ToastMixin,
        SharePreferenceMixin,
        EventBusMixin,
        DataBaseMixin {
  int _loadNum = 0;
  int _minLoadNum = 1;
  late BuildContext context;
  late M model;
  bool _isDispose = false;

  bool get isDispose => _isDispose;

  int needLoadingRequestCount = 0;

  bool isLoading = false;

  Function()? showLoadingFun;

  Function? dismissLoadingFun;

  static bool isNeedCatchError = false;

  set minLoadNum(int value) {
    _minLoadNum = value;
  }

  set loadNum(int value) {
    _loadNum = value;
  }

  int get loadNum {
    return _loadNum;
  }

  void notifyPage() {
    if (!_isDispose) {
      loadNum++;
      print("====>loadNum:$loadNum");
      if (_loadNum >= _minLoadNum) {
        print("====>notifyListeners");
        notifyListeners();
      }
    }
  }

  @override
  void init() {
    model = getIt.get<M>();
    setContext(context);
    setIsDispose(false);
  }

  void showLoading(bool isNeedLoading) {
    if (isNeedLoading) {
      needLoadingRequestCount++;
      if (!isLoading) {
        isLoading = true;
        if (showLoadingFun != null) {
          showLoadingFun!.call();
        }
        showLoadingFun?.call();
      }
    }
  }

  void dismissLoading(bool isNeedLoading) {
    if (isNeedLoading) {
      needLoadingRequestCount--;
      if (needLoadingRequestCount == 0) {
        isLoading = false;
        if (dismissLoadingFun != null) {
          dismissLoadingFun!.call();
        }
        dismissLoadingFun?.call();
      }
    }
  }

  /// 发起网络请求,同时处理异常,loading
  void sendRequest<T>(Future<T> future, FutureOr<dynamic> onValue(T value),
      {Function(Exception e)? error, bool isNeedLoading = false}) {
    showLoading(isNeedLoading);
    future.then((t) {
      dismissLoading(isNeedLoading);
      onValue(t);
    });
    if (isNeedCatchError) {
      future.catchError((e) {
        dismissLoading(isNeedLoading);
        print("====>error:$e");
        if (error != null) {
          error(e);
        }
      });
    }
  }

  @override
  void dispose() {
    super.dispose();
    _isDispose = true;
    setIsDispose(_isDispose);
  }
}
复制代码
@injectable
class LoginViewModel extends BaseViewModel<LoginModel> {
  @factoryMethod
  LoginViewModel();

  String loginName = "";
  String psw = "";

  ///登录
  void login() {
    if (loginName.isEmpty) {
      showToast("登录账号不可为空");
    } else if (psw.isEmpty) {
      showToast("登录密码不可为空");
    } else {
      sendRequest<LoginResult>(model.login(loginName, psw), (value) {
        if (value.errorCode == 0) {
          value.data?.let((it) {
            UserInfoSp.getInstance().uid = it.id ?? 0;
            UserInfoSp.getInstance().token = it.token ?? "";
            UserInfoSp.getInstance().userName = it.username ?? "";
          });
          pop();
          push(MainPage());
        } else {
          showToast(value.errorMsg!);
        }
      }, isNeedLoading: true);
    }
  }
}
复制代码

使用的第三方框架

  • 1. injectable
    配合get_it框架,在编译时生成代码,实现依赖注入
  • 2.dio
    实现网络请求
  • 3.get_it
    实现依赖注入
  • 4.retrofit
    结合dio实现网络请求,编译时生成网络请求的代码
  • 5.logger
    日志打印
  • 6.toast
    吐司
  • 7.event_bus
    实现不同页面和组件的通信
  • 8.json_serializable
    结合json_annotation实现json数据序列化
  • 9.extended_image
    实现网络图片的加载,强大的官方 Image 扩展组件, 支持加载以及失败显示,缓存网络图片,缩放拖拽图片,绘制自定义效果等功能
  • 10.webview_flutter
    实现网页的加载
  • 11.shared_preferences
    简单的数据持久存储
  • 12.pull_to_refresh
    实现下拉刷新和分页加载
  • 13.floor
    数据库,使用类似于retrofit
  • 14.flutter_swiper
    图片轮播

使用的架构和基础封装

  • 基于Flutter2.0,语法空安全
  • 结合Provider实现MVVM架构,封装了BaseState,BaseStatefulWidget,BaseViewModel
  • 结合模板方法模式,泛型,Mixin,依赖注入等方式,封装了大量重复的逻辑,简化了开发难度
  • Mixin类的封装:目前包含NavigatorMixin,ToastMixin,SharePreferenceMixin,EventBusMixin,DataBaseMixin
  • 基础Widget的封装:例如BottomDialog,CenterDialog,EnsureAndCancelDialog,LoadingDialog,PopupWindow,CommonWrap,LazyIndexedStack等等
  • BaseViewModel统一网络请求,统一发起网络请求,同时处理异常,loading
  • 使用扩展函数:扩展自Object,List,int,Widget,让代码更加简洁优雅

后期规划

1.路由,实现各模块,各业务的解耦
2.组件化
3.内存泄漏检测
4.埋点框架
5.各种炫酷动画
6.性能优化

QQ交流群

群号码:770892444

文章分类
Android
文章标签