flutter完整项目结构(可以直接参照或者复用)

  1. 主要涉及到三大块
    router , state , api

1.1 路由使用了dio: ^3.0.10

目录结构如下

****

  1. application.dart
    作用 : 用于静态化
    import 'package:fluro/fluro.dart';
    class Application {
      static Router router;
    }
    

使用

Application.router
  1. navigator_util.dart
    作用 : 这个里面主要是进行路由跳转方法的公共书写
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import 'package:app/ui/page/index_page.dart';
import 'package:app/ui/page/login.dart';
import './application.dart';
import './routes.dart';

/**
 * 这个里面主要是进行路由跳转方法的公共书写
 */

class NavigatorUtil {
  // 返回
  static void goBack(BuildContext context) {
    /// 其实这边调用的是 Navigator.pop(context);
    Application.router.pop(context);
  }

  // 带参数的返回
  static void goBackWithParams(BuildContext context, result) {
    Navigator.pop(context, result);
  }

  // 路由返回指定页面
  static void goBackUrl(BuildContext context, String title) {
    Navigator.popAndPushNamed(context, title);
  }

  // 跳转到主页面
  static void goIndexPage(BuildContext context) {
    Application.router.navigateTo(context, Routes.indexPage, replace: true);
  }

  /// 跳转到 转场动画 页面 , 这边只展示 inFromLeft ,剩下的自己去尝试下,
  /// 框架自带的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom
  static Future jump(BuildContext context, String title) {
    return Application.router.navigateTo(context, title, transition: TransitionType.inFromRight);

    /// 指定了 转场动画
  }

  /// 框架自带的有 native,nativeModal,inFromLeft,inFromRight,inFromBottom,fadeIn,custom
  static Future jumpLeft(BuildContext context, String title) {
    return Application.router
        .navigateTo(context, title, transition: TransitionType.inFromLeft);

    /// 指定了 转场动画
  }

  static Future jumpRemove(BuildContext context) {
    return Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(
          builder: (context) => IndexPage(),
        ),
            (route) => route == null);
  }

  /// 自定义 转场动画
  static Future gotransitionCustomDemoPage(BuildContext context, String title) {
    var transition = (BuildContext context, Animation<double> animation,
        Animation<double> secondaryAnimation, Widget child) {
      return new ScaleTransition(
        scale: animation,
        child: new RotationTransition(
          turns: animation,
          child: child,
        ),
      );
    };
    return Application.router.navigateTo(context, title,
        transition: TransitionType.custom,

        /// 指定是自定义动画
        transitionBuilder: transition,

        /// 自定义的动画
        transitionDuration: const Duration(milliseconds: 600));

    /// 时间
  }

  /// 使用 IOS 的 Cupertino 的转场动画,这个是修改了源码的 转场动画
  /// Fluro本身不带,但是 Flutter自带
  static Future gotransitionCupertinoDemoPage(
      BuildContext context, String title) {
    return Application.router
        .navigateTo(context, title, transition: TransitionType.cupertino);
  }

  // 跳转到主页面IndexPage并删除当前路由
  static void goToHomeRemovePage(BuildContext context) {
    Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(
          builder: (context) => IndexPage(),
        ),
            (route) => route == null);
  }

  // 跳转到登录页并删除当前路由
  static void goToLoginRemovePage(BuildContext context) {
    Navigator.of(context).pushAndRemoveUntil(
        MaterialPageRoute(
          builder: (context) => Login(),
        ),
            (route) => route == null);
  }
}

使用

NavigatorUtil.jump(context, '/indexPage')
/********************************/
NavigatorUtil.jumpLeft(context, '/normalPage') //附带路由动画, 界面从左边进来
  1. router_handler.dart
    作用 : handler就是每个路由的规则,编写handler就是配置路由规则,比如我们要传递参数,参数的值是什么,这些都需要在Handler中完成。

```bash
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import 'package:app/ui/page/index_page.dart';
import 'package:app/ui/page/login.dart';
import 'package:app/ui/page/normal_page.dart';
import 'package:app/ui/page/routing_reference.dart';

/**
 * handler就是每个路由的规则,编写handler就是配置路由规则,比如我们要传递参数,参数的值是什么,这些都需要在Handler中完成。
 */

// 首页
Handler indexPageHanderl = Handler(
  handlerFunc: (BuildContext context, Map<String, List<String>> params) {
    return IndexPage();
  },
);

// 正常路由跳转
Handler normalPageHanderl = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
      return NormalPage();
    }
);

// 路由传参
Handler routingReferenceHanderl = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
      String id = params['id'].first;
      return RoutingReference(id: id);
    }
);

// 登陆页面
Handler loginHanderl = Handler(
    handlerFunc: (BuildContext context, Map<String, List<String>> params) {
      return Login();
    }
);

 4. routes.dart
 作用 : 路由的总配置
           涉及到管理路由的名称, 以及管理路由跳转到那个handler规则中
 

```bash
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import 'package:app/routers/router_handler.dart';

class Routes {
  static String root = '/';
  static String indexPage = '/indexPage';
  static String normalPage = '/normalPage';
  static String routingReference = '/routingReference';
  static String login = '/login';
  static void configureRoutes(Router router) {
    router.notFoundHandler = new Handler(
      handlerFunc: (BuildContext context, Map<String, List<String>> params) {
        print('ERROR====>ROUTE WAS NOT FONUND!!!'); // 找不到路由,跳转404页面
        print('找不到路由,404');
      },
    );

    // 路由页面配置
    router.define(indexPage, handler: indexPageHanderl);
    router.define(normalPage, handler: normalPageHanderl);
    router.define(routingReference, handler: routingReferenceHanderl);
    router.define(login, handler: loginHanderl);
  }
}
  1. 以上整个路由目录结构搭建完毕, 接下来注入main.dart中
// 路由架构
// 参照链接 https://segmentfault.com/a/1190000021488577
// 参照动画 https://blog.csdn.net/z591102/article/details/107839695
import 'package:fluro/fluro.dart';
import 'package:app/routers/application.dart';
import 'package:app/routers/routes.dart';
import "package:app/routers/navigator_util.dart";

void main() {
  // 禁用提示
  Provider.debugCheckInvalidValueType = null;

  // widget和flutter初始化
  WidgetsFlutterBinding.ensureInitialized();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
	/*****************************/
	// 路由部分代码
    final router = Router();
    Routes.configureRoutes(router);
    Application.router = router;
    /*****************************/

    return  MultiProvider(
        providers : providers,
        child : MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        )
    );
  }
}

使用路由

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

var style = TextStyle(color: Colors.white);
class _MyHomePageState extends State<MyHomePage> { 

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Container(
              child: Center(
                  child: Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: Container(
                      color: Colors.redAccent,
                      height: 48,
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: <Widget>[

                          RaisedButton(
                            onPressed: () => {
                              NavigatorUtil.jump(context, '/indexPage')
                            },
                            child: Text('routerRight'),
                          ),
                          RaisedButton(
                            onPressed: () => {
                              NavigatorUtil.jumpLeft(context, '/normalPage')
                            },
                            child: Text('routerLeft'),
                          ),
                        ],
                      ),
                    ),
                  )
              )
          ),
          Container(
            color: Colors.deepOrangeAccent,
              child: Center(
                  child: Text('$src', style: style),
              )
          ),
        ],
      ),
 // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

如何定义一个新的路由
两个步骤
1 . 在router_handler.dart中引入要跳转的组件 , 定制一个新的路由规则
2. 在routes.dart中 新增一个路由地址 , 使用 router.define 注册路由即可

1.2 state使用了provider: ^4.3.2+2

目录结构如下

在这里插入图片描述

  1. provider_manager.dart
    作用 : 统一管理state
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import "package:app/view_model/test_model.dart";

List<SingleChildWidget> providers = [
  ...independentServices,
  ...dependentServices,
  ...uiConsumableProviders
];

/// 独立的model
List<SingleChildWidget> independentServices = [
  ChangeNotifierProvider<TestModel>(
    create: (context) => TestModel(),
  ),
  ChangeNotifierProvider<TestMode2>(
    create: (context) => TestMode2(),
  ),
//  ChangeNotifierProvider<LocaleModel>(
//    create: (context) => LocaleModel(),
//  ),
//  ChangeNotifierProvider<GlobalFavouriteStateModel>(
//    create: (context) => GlobalFavouriteStateModel(),
//  )
];

/// 需要依赖的model
///
/// UserModel依赖globalFavouriteStateModel
List<SingleChildWidget> dependentServices = [
//  ChangeNotifierProxyProvider<GlobalFavouriteStateModel, UserModel>(
//    create: null,
//    update: (context, globalFavouriteStateModel, userModel) =>
//    userModel ??
//        UserModel(globalFavouriteStateModel: globalFavouriteStateModel),
//  )
];

List<SingleChildWidget> uiConsumableProviders = [
//  StreamProvider<User>(
//    builder: (context) => Provider.of<AuthenticationService>(context, listen: false).user,
//  )
];

  1. provider_widget.dart 和 provider_widget_selector.dart 是一样的, 都是基于provider进一步封装 , 封装的意义在于, 可以更加方便的颗粒化的去build

provider_widget.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

/// Provider封装类
///
/// 方便数据初始化
/// 另外发现进一步封装,都是使用了Consumer来进行包裹, 那么这总控制会更加颗粒化的去build
class ProviderWidget<T extends ChangeNotifier> extends StatefulWidget {
  final ValueWidgetBuilder<T> builder;
  final T model;
  final Widget child;
  final Function(T model) onModelReady;
  final bool autoDispose;

  ProviderWidget({
    Key key,
    @required this.builder,
    @required this.model,
    this.child,
    this.onModelReady,
    this.autoDispose: true,
  }) : super(key: key);

  _ProviderWidgetState<T> createState() => _ProviderWidgetState<T>();
}

class _ProviderWidgetState<T extends ChangeNotifier>
    extends State<ProviderWidget<T>> {
  T model;

  @override
  void initState() {
    model = widget.model;
    widget.onModelReady?.call(model);
    super.initState();
  }

  @override
  void dispose() {
    if (widget.autoDispose) model.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<T>.value(
      value: model,
      child: Consumer<T>(
        builder: widget.builder,
        child: widget.child,
      ),
    );
  }
}

class ProviderWidget2<A extends ChangeNotifier, B extends ChangeNotifier>
    extends StatefulWidget {
  final Widget Function(BuildContext context, A model1, B model2, Widget child)
  builder;
  final A model1;
  final B model2;
  final Widget child;
  final Function(A model1, B model2) onModelReady;
  final bool autoDispose;

  ProviderWidget2({
    Key key,
    @required this.builder,
    @required this.model1,
    @required this.model2,
    this.child,
    this.onModelReady,
    this.autoDispose,
  }) : super(key: key);

  _ProviderWidgetState2<A, B> createState() => _ProviderWidgetState2<A, B>();
}

class _ProviderWidgetState2<A extends ChangeNotifier, B extends ChangeNotifier>
    extends State<ProviderWidget2<A, B>> {
  A model1;
  B model2;

  @override
  void initState() {
    model1 = widget.model1;
    model2 = widget.model2;
    widget.onModelReady?.call(model1, model2);
    super.initState();
  }

  @override
  void dispose() {
    if (widget.autoDispose) {
      model1.dispose();
      model2.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider<A>.value(value: model1),
          ChangeNotifierProvider<B>.value(value: model2),
        ],
        child: Consumer2<A, B>(
          builder: widget.builder,
          child: widget.child,
        ));
  }
}

provider_widget_selector.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

/// Provider封装类
///
/// 方便数据初始化
class ProviderWidget<T extends ChangeNotifier > extends StatefulWidget {
  final ValueWidgetBuilder builder;
  final Function(BuildContext, T) selector;
  final T model;
  final Widget child;
  final Function(T model) onModelReady;
  final bool autoDispose;

  ProviderWidget({
    Key key,
    @required this.builder,
    @required this.model,
    this.selector,
    this.child,
    this.onModelReady,
    this.autoDispose,
  }) : super(key: key);

  _ProviderWidgetState<T> createState() => _ProviderWidgetState<T>();
}

class _ProviderWidgetState<T extends ChangeNotifier>
    extends State<ProviderWidget<T>> {
  T model;

  @override
  void initState() {
    model = widget.model;
    widget.onModelReady?.call(model);
    super.initState();
  }

  @override
  void dispose() {
    if (widget.autoDispose) model.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<T>.value(
      value: model,
      child: Selector<T, Symbol>(
        selector: widget.selector,
        builder: widget.builder,
        child: widget.child,
      ),
    );
  }
}



  1. test_model.dart 定义一个state
    作用 : 数据的管理源都来自这里 , 继承ChangeNotifier 是因为要有可以执行的notifyListeners方法 , 该方法执行才会进行ui build重新刷新
import 'package:flutter/cupertino.dart';

class TestModel extends ChangeNotifier {
  String title = "";
  String get value => title;
  TestModel({this.title = "2"});


  setTitle(value){
    title = title + value;
    notifyListeners();
  }

  removeTitle(){
    title = "";
    notifyListeners();
  }
}

class TestMode2 extends ChangeNotifier {
  String title = "";
  String get value => title;
  TestMode2({this.title = "2"});


  setTitle(value){
    title = title + value;
    notifyListeners();
  }

  removeTitle(){
    title = "";
    notifyListeners();
  }
}
  1. 在main.dart中引入并注入到顶部
// State架构
// 参考连接 : https://juejin.im/post/6872153613776060424#heading-4
// 注意: 通过Provider来获取被管理的数据的三种方式:Provider.of,Consumer和Selector,它们的功能完全一致,区别仅仅在于刷新的控制粒度。
import 'package:provider/provider.dart';
import 'package:app/config/provider_manager.dart'

void main() {
  // 禁用提示
  Provider.debugCheckInvalidValueType = null;

  // widget和flutter初始化
  WidgetsFlutterBinding.ensureInitialized();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    final router = Router();
    Routes.configureRoutes(router);
    Application.router = router;
	
    /**
     * 顶层使用MultiProvider, 注入providers 即可
     */
    return  MultiProvider(
        providers : providers,
        child : MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        )
    );
  }
}

使用

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

var style = TextStyle(color: Colors.white);

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          ProviderWidget<TestModel>(
              model: TestModel(title : "3"),
              builder: (context, TestModel, child){
                print("TestMode1重新build");
                return Container(
                    child: Center(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Container(
                            color: Colors.redAccent,
                            height: 48,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: <Widget>[
                                Text('Child1', style: style),
                                Text('Model data: ${ TestModel.title}', style: style),
                                RaisedButton(
                                  onPressed: () => TestModel.setTitle("2"),
                                  child: Text('add'),
                                ),
                                RaisedButton(
                                  onPressed: () => TestModel.removeTitle(),
                                  child: Text('remove'),
                                ),
                              ],
                            ),
                          ),
                        )
                    )
                );
              }
          ),
          ProviderWidget<TestMode2>(
              model: TestMode2(title : "4"),
              builder: (context, TestModel, child){
                print("TestMode2重新build");
                return Container(
                    child: Center(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Container(
                            color: Colors.blueAccent,
                            height: 48,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: <Widget>[
                                Text('Child2', style: style),
                                Text('Model data: ${ TestModel.title}', style: style),
                                RaisedButton(
                                  onPressed: () => TestModel.setTitle("2"),
                                  child: Text('add'),
                                ),
                                RaisedButton(
                                  onPressed: () => TestModel.removeTitle(),
                                  child: Text('remove'),
                                ),
                              ],
                            ),
                          ),
                        )
                    )
                );
              }
          ),
        ],
      ),
  // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}



  1. 如果要新增一个state ,两个步骤
    1. view_model目录下创建一个新的state
    2. provider_manager.dart 引入并注入即可

1.3 api使用了dio: ^3.0.10

目录结构

在这里插入图片描述

  1. NWMethod.dart
    作用 : 对请求进行了枚举
enum NWMethod {
  GET,
  POST,
  DELETE,
  PUT
}
//使用:NWMethodValues[NWMethod.POST]
const NWMethodValues = {
  NWMethod.GET: "get",
  NWMethod.POST: "post",
  NWMethod.DELETE: "delete",
  NWMethod.PUT: "put"
};

  1. ErrorEntity.dart
    作用 : 对报错的返回进行了封装,可根据实际业务场景自行修改
class ErrorEntity {
  String code;
  String message;
  ErrorEntity({this.code, this.message});
}
  1. EntityFactory.dart
    作用 : 对返回的数据进行统一序列化的位置
// json转换辅助工厂,把json转为T
import "package:app/model/user_login.dart";  
class EntityFactory {
  static T generateOBJ<T>(json) {
    if (json == null) {
      return null;
    }
    else if (T.toString() == "UserLogin") {
      final res =  UserLogin.fromJson(json) as T ;
      return res ;
    }
    else {
      return json as T;
    }
  }
}

  1. DioManager.dart
    作用 : 对请求做了统一的封装
import 'package:dio/dio.dart';
import "package:app/api/BaseEntity.dart";
import "package:app/api/BaseListEntity.dart";
import "package:app/api/baseApi.dart";
import "package:app/api/NWMethod.dart";
import "package:app/api/ErrorEntity.dart";

/**
 *  dio封装参考这一篇 https://juejin.im/post/6844903708757590024#heading-4
 */

class DioManager {
  static final DioManager _shared = DioManager._internal();
  factory DioManager() => _shared;
  Dio dio;
  DioManager._internal() {
    if (dio == null) {
      BaseOptions options = BaseOptions(
        baseUrl: NWApi.baseApi,
        contentType: Headers.jsonContentType,
        responseType: ResponseType.json,
        receiveDataWhenStatusError: false,
        connectTimeout: 30000,
        receiveTimeout: 3000,
      );
      dio = Dio(options);
    }
  }

  // 请求,返回参数为 T
  // method:请求方法,NWMethod.POST等
  // path:请求地址
  // params:请求参数
  // success:请求成功回调
  // error:请求失败回调
  Future request<T>(NWMethod method, String path, {Map params, Function(T) success, Function(ErrorEntity) error}) async {
    try {
      Response response = await dio.request(path, data: params, options: Options(method: NWMethodValues[method]));
      if (response != null) {
        BaseEntity entity = BaseEntity<T>.fromJson(response.data);
        if (entity.code == "000000") {
          success(entity.data);
          return entity.data;
        } else {
          error(ErrorEntity(code: entity.code, message: entity.message));
        }
      } else {
        error(ErrorEntity(code: "-1", message: "未知错误"));
      }
    } on DioError catch(e) {
      error(createErrorEntity(e));
    }
  }

  // 请求,返回参数为 List
  // method:请求方法,NWMethod.POST等
  // path:请求地址
  // params:请求参数
  // success:请求成功回调
  // error:请求失败回调
  Future requestList<T>(NWMethod method, String path, {Map params, Function(List<T>) success, Function(ErrorEntity) error}) async {
    try {
      Response response = await dio.request(path, data: params, options: Options(method: NWMethodValues[method]));
      if (response != null) {
        BaseListEntity entity = BaseListEntity<T>.fromJson(response.data);
        if (entity.code == 0) {
          success(entity.data);
        } else {
          error(ErrorEntity(code: entity.code, message: entity.message));
        }
      } else {
        error(ErrorEntity(code: "-1", message: "未知错误"));
      }
    } on DioError catch(e) {
      error(createErrorEntity(e));
    }
  }

  // 错误信息
  ErrorEntity createErrorEntity(DioError error) {
    switch (error.type) {
      case DioErrorType.CANCEL:{
        return ErrorEntity(code:" -1", message: "请求取消");
      }
      break;
      case DioErrorType.CONNECT_TIMEOUT:{
        return ErrorEntity(code: "-1", message: "连接超时");
      }
      break;
      case DioErrorType.SEND_TIMEOUT:{
        return ErrorEntity(code: "-1", message: "请求超时");
      }
      break;
      case DioErrorType.RECEIVE_TIMEOUT:{
        return ErrorEntity(code: "-1", message: "响应超时");
      }
      break;
      case DioErrorType.RESPONSE:{
        try {
          int errCode = error.response.statusCode;
          String errMsg = error.response.statusMessage;
          return ErrorEntity(code: "$errCode", message: errMsg);
//          switch (errCode) {
//            case 400: {
//              return ErrorEntity(code: errCode, message: "请求语法错误");
//            }
//            break;
//            case 403: {
//              return ErrorEntity(code: errCode, message: "服务器拒绝执行");
//            }
//            break;
//            case 404: {
//              return ErrorEntity(code: errCode, message: "无法连接服务器");
//            }
//            break;
//            case 405: {
//              return ErrorEntity(code: errCode, message: "请求方法被禁止");
//            }
//            break;
//            case 500: {
//              return ErrorEntity(code: errCode, message: "服务器内部错误");
//            }
//            break;
//            case 502: {
//              return ErrorEntity(code: errCode, message: "无效的请求");
//            }
//            break;
//            case 503: {
//              return ErrorEntity(code: errCode, message: "服务器挂了");
//            }
//            break;
//            case 505: {
//              return ErrorEntity(code: errCode, message: "不支持HTTP协议请求");
//            }
//            break;
//            default: {
//              return ErrorEntity(code: errCode, message: "未知错误");
//            }
//          }
        } on Exception catch(_) {
          return ErrorEntity(code: "-1", message: "未知错误");
        }
      }
      break;
      default: {
        return ErrorEntity(code:" -1", message: error.message);
      }
    }
  }
}

  1. BaseListEntity.dart
    作用 : 当返回的是这种格式时 {“code”: 0, “message”: “”, “data”: []},进行序列化操作 , 依赖于EntityFactory.dart
import "package:app/api/EntityFactory.dart";
// 当返回的是这种格式时 {“code”: 0, “message”: “”, “data”: []}
class BaseListEntity<T> {
  String code;
  String message;
  List<T> data;

  BaseListEntity({this.code, this.message, this.data});

  factory BaseListEntity.fromJson(json) {
    List<T> mData = List();
    if (json['data'] != null) {
      //遍历data并转换为我们传进来的类型
      (json['data'] as List).forEach((v) {
        mData.add(EntityFactory.generateOBJ<T>(v));
      });
    }

    return BaseListEntity(
      code: json["code"],
      message: json["msg"],
      data: mData,
    );
  }
}
  1. BaseEntity.dart
    作用 : 当返回的数据是这种格式的时候 {“code”: 0, “message”: “”, “data”: {}},进行序列化操作 , 依赖于EntityFactory.dart
import "package:app/api/EntityFactory.dart";
// 当返回的数据是这种格式的时候  {“code”: 0, “message”: “”, “data”: {}}
class BaseEntity<T> {
  String code;
  String message;
  T data;

  BaseEntity({this.code, this.message, this.data});

  factory BaseEntity.fromJson(json) {
    return BaseEntity(
      code: json["code"],
      message: json["msg"],
      // data值需要经过工厂转换为我们传进来的类型
      data: EntityFactory.generateOBJ<T>(json) ,
    );
  }
}

  1. baseApi.dart
    作用 : 对api地址进行统一的管理
class NWApi {
  static final baseApi = "https://***.***/";
  static final loginPath = "/user/login";
}

  1. Api.dart
    作用 : 所有的api请求调用的方法都在这里面
import "package:app/api/baseApi.dart";
import "package:app/api/DioManager.dart";
import "package:app/api/NWMethod.dart";
import "package:app/model/user_login.dart";
class Api {
  ///示例请求
  static UserLoginApi(Map<String , dynamic> param ) async {
    return await DioManager().request<UserLogin>(
            NWMethod.POST,
            NWApi.loginPath,
            params: param,
            success: (data) {

            },
            error: (error) {
              print("error code = ${error.code}, massage = ${error.message}");
            }
          );
      }
}

  1. 使用
// Api架构
// 参照链接 https://juejin.im/post/6844903708757590024#heading-4
import "package:app/api/Api.dart";

    void _testRequest() async {
	    final res =  await Api.UserLoginApi({
	        "user_name": "1111",
	        "user_pwd": "1111"
	      });
	    this.setState(() {
	      src =  "姓名" + res.data.userName + "\n"
	             + "密码" + res.data.userPwd + "\n"
	             + "userNickName" + res.data.userNickName + "\n"
	             + "userQq" + res.data.userQq + "\n"
	             + "userEmail" + res.data.userEmail + "\n"
	             + "userPhone" + res.data.userPhone + "\n"
	             +  "token = " + res.data.token + "\n";
	    });
  }

如果要新建一个api,两个步骤

  1. 在baseApi.dart中新增一个地址
  2. 在Api.dart创建一个方法

github : https://github.com/2547881370/flutter_structure

Flutter项目结构推荐是遵循一种清晰、模块化和可维护性的架构。以下是一个常见的Flutter项目结构推荐: 1. lib文件夹:这个文件夹是主要的代码目录,包含所有的Flutter代码文件。 2. main.dart文件:这个文件是Flutter应用的入口点,它包含了应用的初始化和启动逻辑。 3. models文件夹:这个文件夹用于存放数据模型,比如用户、商品等,通常会创建一个类来代表每个模型对象。 4. views文件夹:这个文件夹用于存放所有的视图文件,每个视图都应有一个对应的.dart文件,用来处理界面布局和交互逻辑。 5. widgets文件夹:这个文件夹用于存放所有的自定义小部件,它们是Flutter的基本构建块,可以重用和组合来构建各种界面。 6. services文件夹:这个文件夹用于存放与后台通信、数据库访问等服务相关的代码,可以使用单例模式来管理这些服务。 7. utils文件夹:这个文件夹用于存放各类工具函数,比如日期处理、网络请求等,可以以函数库的形式提供给其他部分使用。 8. assets文件夹:这个文件夹用于存放应用所需的静态资源,比如图片、字体文件等。 9. tests文件夹:这个文件夹用于存放单元测试代码,以确保应用的质量和稳定性。 以上是一种常见的Flutter项目结构推荐,它能够提供清晰的代码组织和模块化的开发方式,同时也便于协作和维护。但实际项目中,根据具体需求和团队的喜好,可能会进行适当的调整和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值