Flutter自定义model实体类

在某些场景下,我们可能需要自定义Flutter model实体类,来创建更加结构化和有组织的代码,提高代码的可重用性,并增强Flutter应用程序的整体可维护性。

  1. 自定义小部件:在创建自己的小部件时,可能需要定义自定义数据类型来封装小部件的特定数据和行为。

  2. API集成:在使用API时,您可能需要定义自定义数据类型,以便以结构化的方式解析和表示响应数据。这有助于更有效地处理和操作数据。

  3. 状态管理:在像Provider或Riverpod这样的状态管理解决方案中,你可以定义自定义数据类型来表示应用程序的状态,并相应地更新它。

  4. 表单验证:在构建表单时,您可能希望定义自定义数据类型来表示表单字段并对输入值执行验证。

一、认识Flutter的model

1、model类的结构

一般常用的会有以下几个

  • 1、【必须】属性

  • 2、【必须】构造方法

  • 3、【必须】fromJson: 序列化 -> model实体类

  • 4、【可省】toMap(toJson):model实体类 -> 序列化 (如果不需要序列化可以缺省)

上述中:toMap也可写成toJson。

实际上在Flutter中,约定是在将对象转换为json可序列化映射时更多地使用toJson()而不是toMap()。但是,只要方法的功能清楚,实际的方法名称并不重要。

import 'package:wechat/tools/convert_util.dart';

class OrderDataEntity {
  //【必须】属性
  String? type;

  //【必须】构造方法
  OrderDataEntity({
    required this.type,
  });
  
  //【必须】Map转Model
  factory OrderDataEntity.fromJson(Map<String, dynamic> jsonRes) {
    return OrderDataEntity(
      // 这里根据情况选择是否可以为空,然后指定默认值
      type: asT<String>(jsonRes['type']),
      // type: asT<String>(jsonRes['type']) ?? '',
    );
  }

  //【可省】model转Map
  Map<String, dynamic> toJson() => {
    'type': type,
  };
}

除了常用的还有不常用的

  • 5、【可省】toString:这个重写的Object的方法

toString一般不需要重写,使用orderDataEntity.toJson().toString()替代即可

  • 6、【可省】copy:拷贝数据时可实现copy方法
//【可省】一般不需要重写,使用toJson.toString()替代

String toString() {
  return 'OrderDataEntity{name: $type}';
}

//【可省】提供copy功能
OrderDataEntity copy() {
  return OrderDataEntity(
    type: type,
  );
}

2、可空类型处理

对于变量声明,如果是网络返回的建议声明为可空类型,如果是自定义组件使用建议声明为不可空类型。

  • 可空类型
String? type;
// 对应的构建model
type: asT<String>(jsonRes['type']),
  • 不可空类型
String type;
// 对应的构建model
type: asT<String>(jsonRes['type'])??'',

二、属性为基本数据

对于简单数据类型可以直接转换

  • 数字:num、int、double

  • 字符串:String

  • 布尔:bool

不同类型在使用上的区别

1、替换属性类型

2、替换fromJson中的泛型与默认值(不可空类型才需要默认值)

// 示例
String type;
num age;

type: asT<String>(jsonRes['type']) ?? '',
age: asT<num>(jsonRes['age']) ?? 0,

三、属性为集合

1、集合List<String>

import 'package:wechat/tools/convert_util.dart';

class OrderDataEntity {
  // 属性
  String? type;
  List<String>? orderList;

  // 构造方法
  OrderDataEntity({
    required this.type,
    required this.orderList,
  });

  // model转Map
  Map<String, dynamic> toJson() => {
        'type': type,
        'orderList': orderList,
      };

  // Map转Model
  factory OrderDataEntity.fromJson(Map<String, dynamic> jsonRes) {
    List<OrderDataOrderList> orderList = [];
    for (final dynamic item in (jsonRes['orderList'] ?? [])) {
      orderList
          .add(OrderDataOrderList.fromJson(asT<Map<String, dynamic>>(item)!));
    }
    return OrderDataEntity(
      type: asT<String>(jsonRes['type']) ?? '',
      orderList: asListT<String>(jsonRes['orderList']),
    );
  }
}

2、嵌套List<Map<String, dynamic>>

class OrderDataOrderList {
  List<Map<String, dynamic>>? saleGoodsAppearanceImagesList;

  OrderDataOrderList({
    required this.saleGoodsAppearanceImagesList,
  });

  Map<String, dynamic> toJson() => {
        'saleGoodsAppearanceImagesList': saleGoodsAppearanceImagesList,
      };

  factory OrderDataOrderList.fromJson(Map<String, dynamic> jsonRes) {
    List<Map<String, dynamic>>? saleGoodsAppearanceImagesList;
    if (jsonRes['saleGoodsAppearanceImagesList'] != null) {
      saleGoodsAppearanceImagesList = List<Map<String, dynamic>>.from(
          jsonRes['saleGoodsAppearanceImagesList'].map((item) {
        return Map<String, dynamic>.from(item);
      }).toList());
    }

    return OrderDataOrderList(
      saleGoodsAppearanceImagesList: saleGoodsAppearanceImagesList,
    );
  }
}

四、属性为model

1、model

这个相当于套娃,

1、在生成toJson时调用子model的toJson即可

2、在生成tfromJson时调用子model的fromJson即可

import 'package:wechat/tools/convert_util.dart';

class OrderDataEntity {
  // 属性
  String? type;
  OrderDataOrderList? orderList;

  // 构造方法
  OrderDataEntity({
    required this.type,
    required this.orderList,
  });

  // model转Map
  Map<String, dynamic> toJson() => {
        'type': type,
        'orderList': orderList?.toJson(),
      };

  // Map转Model
  factory OrderDataEntity.fromJson(Map<String, dynamic> jsonRes) {
    return OrderDataEntity(
      type: asT<String>(jsonRes['type']) ?? '',
      orderList: OrderDataOrderList.fromJson(jsonRes['orderList']),
    );
  }
}

class OrderDataOrderList {
  int? id;

  OrderDataOrderList({
    required this.id,
  });

  Map<String, dynamic> toJson() => {
        'id': id,
      };

  factory OrderDataOrderList.fromJson(Map<String, dynamic> jsonRes) {
    return OrderDataOrderList(
      id: asT<int>(jsonRes['id']),
    );
  }
}

2、嵌套List<Model>

// 方法1:使用工具asListT工具
factory OrderDataEntity.fromJson(Map<String, dynamic> jsonRes) {
  return OrderDataEntity(
    orderList: asListT<OrderDataOrderList>(jsonRes['orderList'],
        fromJson: (json) => OrderDataOrderList.fromJson(json)),
  );
}

// 方法2:等价于自己遍历解析
factory OrderDataEntity.fromJson(Map<String, dynamic> jsonRes) {
  List<OrderDataOrderList> orderList = [];
  for (final dynamic item in (jsonRes['orderList'] ?? [])) {
    orderList
        .add(OrderDataOrderList.fromJson(asT<Map<String, dynamic>>(item)!));
  }
  return OrderDataEntity(
    orderList: orderList,
  );
}

完整示例

import 'package:wechat/tools/convert_util.dart';

class OrderDataEntity {
  // 属性
  String? type;
  List<OrderDataOrderList>? orderList;

  // 构造方法
  OrderDataEntity({
    required this.type,
    required this.orderList,
  });

  // model转Map
  Map<String, dynamic> toJson() => {
        'type': type,
        'orderList': orderList?.map((item) => item.toJson()).toList(),
      };

  // Map转Model
  factory OrderDataEntity.fromJson(Map<String, dynamic> jsonRes) {
    return OrderDataEntity(
      type: asT<String>(jsonRes['type']) ?? '',
      orderList: asListT<OrderDataOrderList>(jsonRes['orderList'],
          fromJson: (json) => OrderDataOrderList.fromJson(json)),
    );
  }
}

class OrderDataOrderList {
  int? id;

  OrderDataOrderList({
    required this.id,
  });

  Map<String, dynamic> toJson() => {
        'id': id,
      };

  factory OrderDataOrderList.fromJson(Map<String, dynamic> jsonRes) {
    return OrderDataOrderList(
      id: asT<int>(jsonRes['id']),
    );
  }
}

五、工具类convert_util.dart

import 'dart:convert';

import 'package:flutter/foundation.dart';

void tryCatch(Function? f) {
  try {
    f?.call();
  } catch (e, _) {
    debugPrint('$e');
  }
}

class FFConvert {
  FFConvert._();

  static T? convert<T extends Object?>(dynamic value) {
    if (value == null) {
      return null;
    }
    return json.decode(value.toString()) as T?;
  }
}

T? asT<T extends Object?>(dynamic value, [T? defaultValue]) {
  if (value is T) {
    return value;
  }
  try {
    if (value != null) {
      final String valueS = value.toString();
      if ('' is T) {
        return valueS as T;
      } else if (0 is T) {
        return int.parse(valueS) as T;
      } else if (0.0 is T) {
        return double.parse(valueS) as T;
      } else if (false is T) {
        if (valueS == '0' || valueS == '1') {
          return (valueS == '1') as T;
        }
        return (valueS == 'true') as T;
      } else {
        return FFConvert.convert<T>(value);
      }
    }
  } catch (e, _) {
    debugPrint('asT<$T>,error: $e');
    return defaultValue;
  }

  return defaultValue;
}

List<T>? asListT<T extends Object?>(
  dynamic value, {
  T Function(Map<String, dynamic> json)? fromJson,
  bool allowDirty = false,
}) {
  if (value is! List) return null;

  return value.fold<List<T>>([], (list, element) {
    try {
      if (element == null) {
        return list;
      } else {
        final _parsedValue = fromJson != null ? fromJson(element) : asT<T>(element);
        if (_parsedValue == null && !allowDirty) {
          throw Exception('asListT Parse Error: data: ${jsonEncode(element)}');
        }
        if (_parsedValue != null) list.add(_parsedValue);
      }
    } catch (_) {
      debugPrint('dirty data found: ${jsonEncode(element)}');
      if (!allowDirty) {
        rethrow;
      }
    }

    return list;
  });
}

六、额外数据解析

1、List<Map> -> List<String>

List<Map<String, dynamic>>中抽离List<String>

List<String> orderIdList = goodsList.map((e) => e.orderId ?? "").toList();

2、Map转json字符串

import 'dart:convert';

Map<String, dynamic> myMap = {'key1': 'value1', 'key2': 2};

String jsonString = json.encode(myMap);

print(jsonString); // {"key1":"value1","key2":2}

3、json字符串转Map

import 'dart:convert';

String jsonString = '{"key1":"value1","key2":2}';

Map<String, dynamic> myMap = json.decode(jsonString);

print(myMap); // {key1: value1, key2: 2}

4、List<dynamic>List<Map<String,dynamic>>

List<dynamic> myList = [{'key1': 'value1', 'key2': 2}, {'key1': 'value2', 'key2': 3}];

List<Map<String, dynamic>> myNewList = myList.map((item) => Map<String, dynamic>.from(item)).toList();

print(myNewList); // [{key1: value1, key2: 2}, {key1: value2, key2: 3}]