明天平安夜,來聊一下flutter開發框架mvvm+provider

!android

一.mvvm+provider的介紹

mvvm 模式

provider( Flutter 狀態管理框架)

Provider的核心實際上就是InheritedWidget,它其實是對InheritedWidget的封裝,讓InheritedWidget在數據管理上可以更加方便的被開發者所使用。編程

局部状态和全局状态的划分

InheritedWidget 能實現全局的狀態更新,沒法解決局部的問題。segmentfault

如何使用provider

首先繼承 ChangeNotifierapi

class BaseProvide with ChangeNotifier {

  CompositeSubscription compositeSubscription = CompositeSubscription();


  /// add [StreamSubscription] to [compositeSubscription]
  ///
  /// 在 [dispose]的時候能進行取消
  addSubscription(StreamSubscription subscription){
    compositeSubscription.add(subscription);
  }

  @override
  void dispose() {
    super.dispose();
    compositeSubscription.dispose();
  }
}

class RegisterPageState extends State<RegisterPage>{
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => RegisterModel(),
      child: switchStatusBar2DarkAppbar(
          context: context,
          title: "provider demo",
          child: Container(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                ChildWidgetA(),
                SizedBox(height: 24,),
                ChildWidgetB()
              ],
            ),
          )
      )
    );
  }

}

class ChildWidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    debugPrint('ChildWidgetA build');
    var model = Provider.of<RegisterModel>(context);
    return Container(
      color: Colors.redAccent,
      height: 108,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Text('ChildA', style: new TextStyle(
              color: Colors.black, fontSize: CommounUtil.getSp(15))),
          Text('Model data: ${model.valueA}', style: new TextStyle(
              color: Colors.black, fontSize: CommounUtil.getSp(15))),
          RaisedButton(
            onPressed: () => model.addA(),
            child: Text('add'),
          ),
        ],
      ),
    );
  }
}

class ChildWidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    debugPrint('ChildWidgetB build');
    var model = Provider.of<RegisterModel>(context);
    return Container(
      color: Colors.blueAccent,
      height: 108,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Text('ChildB', style: new TextStyle(
              color: Colors.black, fontSize: CommounUtil.getSp(15))),
          Text('Model data: ${model.valueB}', style: new TextStyle(
              color: Colors.black, fontSize: CommounUtil.getSp(15))),
          RaisedButton(
            onPressed: () => model.addB(),
            child: Text('add'),
          ),
        ],
      ),
    );
  }
}


I/flutter (12301): ChildWidgetB build
I/flutter (12301): ChildWidgetA build
I/flutter (12301): ChildWidgetB build
I/flutter (12301): ChildWidgetA build
複製代碼

這種方式當viewmodel中有一個屬性發生變化時,A和B都會buildmarkdown

單個局部刷新Selector網絡

class ChildWidgetC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    debugPrint('ChildWidgetC build');
    return Selector<RegisterModel, int>(
        selector: (context, value) => value.valueA,
        builder: (BuildContext context, value, Widget child) {
          return Container(
            color: Colors.redAccent,
            height: 108,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                Text('ChildC',
                    style: new TextStyle(
                        color: Colors.black, fontSize: CommounUtil.getSp(15))),
                Text('Model data: $value',
                    style: new TextStyle(
                        color: Colors.black, fontSize: CommounUtil.getSp(15))),
                RaisedButton(
                  onPressed: () => context.read<RegisterModel>().addA(),
                  child: Text('add'),
                ),
              ],
            ),
          );
        });
  }
}

class ChildWidgetD extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    debugPrint('ChildWidgetD build');
    return Container(
      color: Colors.blueAccent,
      height: 108,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Text('ChildD',
              style: new TextStyle(
                  color: Colors.black, fontSize: CommounUtil.getSp(15))),
          Text('Model data: ${context.select((RegisterModel value) => value.valueB)}',
              style: new TextStyle(
                  color: Colors.black, fontSize: CommounUtil.getSp(15))),
          RaisedButton(
            onPressed: () => context.read<RegisterModel>().addB(),
            child: Text('add'),
          ),
        ],
      ),
    );
  }
}
複製代碼

有了Selector以後,就能夠在同一個數據模型中,根據條件,篩選出不一樣的刷新條件了,這樣就能夠避免數據模型中的某個屬性變換而引發的整個數據模型刷新了。app

詳細使用方法參考:pub.flutter-io.cn/packages/pr…框架

二.項目結構

  1. apiless

    --http_util.dart ------------------dio網絡請求初始化封裝async

    --net_util.dart ------------------get和post請求封裝

  2. base

    --app_channel.dart ------------------定義不一樣的開發環境

    --app_config.dart ------------------不一樣的開發環境的地址

    --base_provider.dart ------------------provider基類

    --base_responce.dart ------------------接口返回的數據類型

    --base_widge.dart ------------------基本控件封裝

    --global_provider_manager.dart ------------------全局的model管理

  3. common ------------------ 公共的方法

  4. data ------------------ 接口數據解析

  5. generated------------------國際化代碼

  6. http ------------------接口地址

  7. l10n ------------------字符串

    --intl_en.arb 英文

    --intl_zh.arb 中文

  8. model------------------各個頁面請求model

    --login_repository.dart

  9. res

    --colours.dart------------------顏色的定義

  10. router

    --application.dart------------------初始化router

    --router_handers.dart------------------定義每一個頁面的路由

    --routes.dart-----------------配置路由

  11. ui------------------UI頁面

  12. utils------------------工具類

  13. viewmodel------------------每一個頁面的viewmodel

  14. main_dev.dart,main_test.dart,main_uat.dart,main_online.dart

    ------------------不一樣開發環境的程序入口

三.網絡請求框架dio

class HttpUtil{

  static HttpUtil instance;
  Dio dio;
  BaseOptions options;

  static HttpUtil getInstance() {
    print('getInstance');
    if (instance == null) {
      instance = new HttpUtil();
    }
    return instance;
  }
  HttpUtil() {
    _initDio();
  }


  _initDio()  {
    final String token = AppConfig.appTools.getToken();
    String baseRequestUrl=Channel.baseURL;
    dio = new Dio()
      ..options = BaseOptions(
          baseUrl: baseRequestUrl,
          connectTimeout: 20000,
          receiveTimeout: 20000)
      ..interceptors.add(HeaderInterceptor(token))
      ..interceptors.add(LogInterceptor(responseBody: true, requestBody: true));
  }
}

class HeaderInterceptor extends Interceptor {
  String token="";
  HeaderInterceptor(String token){
    this.token=token;
  }
  @override
  onRequest(RequestOptions options) {
    if (token != null && token.length > 0) {
      options.headers.putIfAbsent('Authorization', () => 'Bearer' + ' ' + token);
    }
    return super.onRequest(options);
  }
}
複製代碼
Stream<BaseResponce> get(String url, {Map<String, dynamic> params}) =>
    Stream.fromFuture(_get(url, params: params)).asBroadcastStream();

Future<BaseResponce> _get(String url, {Map<String, dynamic> params}) async {
  var response = await HttpUtil.getInstance().dio.get(url, queryParameters: params);
  var res = BaseResponce.fromJson(response.data);
  return res;
}


Stream<BaseResponce> post(String url,{dynamic body}) =>
    Stream.fromFuture(_post(url, body)).asBroadcastStream();

Future<BaseResponce> _post(String url, dynamic body) async {
  var response;
  if(body==null){
     response = await HttpUtil.getInstance().dio.post(url);
  }else{
     response = await HttpUtil.getInstance().dio.post(url, data: body);
  }

  var res = BaseResponce.fromJson(response.data);
  if(res.code!=200){

  }
  return res;
}
複製代碼

詳細使用地址:pub.flutter-io.cn/packages/di…

四.不一樣開發環境搭建

默認會有一個main.dart文件

根據四個環境拷貝該文件並命名爲main_dev.dart,main_test.dart,main_uat.dart,main_online.dart

每一個文件初始化不一樣的渠道:

五.國際化

1.添加依賴配置

dependencies:
  flutter:
    sdk: flutter
  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 flutter_localizations: #國際化 sdk: flutter 複製代碼

2.MaterialApp的localizationsDelegates

MaterialApp(
// theme: ThemeData(
// //項目配置字體,其餘主題顏色配置的能夠百度
////  fontFamily: Theme.of(context).platform == TargetPlatform.android? (localModel.localeIndex == 1 ? "HanSans":"DIN") : "IOSGILROY",
// ),
                  debugShowCheckedModeBanner: false,
                  locale: localModel.locale,
                  //國際化工廠代理
                  localizationsDelegates: [
                    // Intl 插件(須要安裝) //S.of(context).title
                    S.delegate,
                    RefreshLocalizations.delegate, //下拉刷新
                    //系統控件 國際化
                    GlobalCupertinoLocalizations.delegate,
                    GlobalMaterialLocalizations.delegate,
                    GlobalWidgetsLocalizations.delegate//文本方向等
                  ],
                  supportedLocales: S.delegate.supportedLocales,
                  home: SpalshPage(),
                ),
複製代碼

3.使用本地化的值

安裝插件flutterIntl

重啓as,菜單欄的Tool下找到Flutter Intl 並選擇Initalize for the project

image-20200819234311852

使用Add Locale生成其餘語言的arb文件

image-20200819234431082

使用S.of(context).autoBySystem 能夠獲取該字符串

六.路由

1.導入依賴包

dependencies:
  flutter:
    sdk: flutter

  # 路由跳轉框架 https://segmentfault.com/a/1190000022349982
  fluro: "^1.6.3"
複製代碼

2.全局初始化

final router = new Router();///初始化路由
Routes.configureRoutes(router);
Application.router = router;
複製代碼

3.定義路由頁面

Handler homeHandler= Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters){
    return homePage();
});

Handler mineHandler= Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters){
  return minePage();
});

Handler loginHandler= Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters){
  return LoginPage();
});

Handler xieyiHandler= Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters){
  String type=parameters['type'].first;
  return WebViewPage(type: type,);
});

Handler registerHandler= Handler(handlerFunc: (BuildContext context, Map<String, List<String>> parameters){
  return RegisterPage();
});
複製代碼

4.配置路徑

class Routes{
  static String home='/home';
  static String mine='/mine';
  static String login='/login';
  static String xieyi='/xieyi/:type';
  static String register='/register';
  static void configureRoutes(Router router){
    router.define(home, handler: homeHandler);
    router.define(mine, handler: mineHandler);
    router.define(login, handler: loginHandler);
    router.define(xieyi, handler: xieyiHandler);
    router.define(register, handler: registerHandler);

  }
}
複製代碼

詳細使用地址:pub.flutter-io.cn/packages/fl…

七.rxdart

響應式編程

簡單例子:

Rx.timer(1, new Duration(milliseconds: 700)).listen((event) {
    requestPerMission(context);
});
複製代碼
相關文章
相關標籤/搜索