Flutter Freezed包fromJson生成对象的runtimeType为何不符合预期?
Freezed 类反序列化后 runtimeType 不符问题
我在研究Flutter的freezed包,使用如下模型类:
import 'package:freezed_annotation/freezed_annotation.dart'; part 'ledger_summary_model.freezed.dart'; part 'ledger_summary_model.g.dart'; @freezed class LedgerSummary with _$LedgerSummary { const factory LedgerSummary({ required int ledgerId, }) = _LedgerSummary; factory LedgerSummary.fromJson(Map<String, dynamic> json) => _$LedgerSummaryFromJson(json); }
测试代码:
LedgerSummary ledgerSummary = const LedgerSummary(ledgerId: 1); LedgerSummary ledgerSummaryAgain = LedgerSummary.fromJson(jsonDecode(jsonEncode(ledgerSummary))); print(ledgerSummaryAgain.runtimeType.toString());
打印结果是_$_LedgerSummary,但我预期是LedgerSummary。
我的pubspec.yaml配置:
name: test_freeze description: A new Flutter project. publish_to: 'none' version: 1.0.0+1 environment: sdk: '>=3.1.0 <4.0.0' dependencies: flutter: sdk: flutter freezed: ^2.4.0 freezed_annotation: ^2.1.0 flutter_localizations: sdk: flutter dart_mappable: dart_mappable_builder: dev_dependencies: flutter_test: sdk: flutter build_runner: ^2.1.0 flutter_launcher_icons: ^0.13.1 flutter_lints: ^2.0.1 flutter: uses-material-design: true
flutter doctor -v输出:
[√] Flutter (Channel stable, 3.13.1, on Microsoft Windows [Version 10.0.19044.3086], locale et-EE) • Flutter version 3.13.1 on channel stable at c:\flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision e1e47221e8 (6 weeks ago), 2023-08-22 21:43:18 -0700 • Engine revision b20183e040 • Dart version 3.1.0 • DevTools version 2.25.0 [√] Windows Version (Installed version of Windows is version 10 or higher) [√] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at C:\Users\pavel\AppData\Local\Android\Sdk • Platform android-34, build-tools 34.0.0 • ANDROID_HOME = C:\Users\pavel\AppData\Local\Android\Sdk • ANDROID_SDK_ROOT = C:\Users\pavel\AppData\Local\Android\Sdk • Java binary at: c:\Program Files\Android\Android Studio\jbr\bin\java • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231) • All Android licenses accepted. [√] Chrome - develop for the web • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe [√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.1.4) • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community • Visual Studio Community 2022 version 17.1.32407.343 • Windows 10 SDK version 10.0.19041.0 [√] Android Studio (version 2022.3) • Android Studio at c:\Program Files\Android\Android Studio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • android-studio-dir = c:\Program Files\Android\Android Studio • Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231) [√] VS Code (version 1.82.2) • VS Code at C:\Users\pavel\AppData\Local\Programs\Microsoft VS Code • Flutter extension version 3.72.0 [√] Connected device (4 available) • sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 14 (API 34) (emulator) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19044.3086] • Chrome (web) • chrome • web-javascript • Google Chrome 116.0.5845.141 • Edge (web) • edge • web-javascript • Microsoft Edge 117.0.2045.43 [√] Network resources • All expected network resources are available. • No issues found!
我想实现一个包含多个freezed类的仓库,把这些类作为泛型对象交给单个滚动视图控制器。
问题原因与解决方案
这是Freezed的正常行为:LedgerSummary是抽象类,_$_LedgerSummary是Freezed自动生成的具体实现类。不管是通过构造函数还是fromJson创建实例,实际运行时类型都是生成的具体类,但实例在类型检查时会被视为LedgerSummary类型。
泛型场景处理方案
如果你的滚动视图控制器需要基于泛型区分不同Freezed类,可以通过以下方式处理:
统一基类标识
定义一个抽象基类,让所有Freezed类实现它:abstract class BaseModel {} @freezed class LedgerSummary with _$LedgerSummary implements BaseModel { const factory LedgerSummary({required int ledgerId}) = _LedgerSummary; factory LedgerSummary.fromJson(Map<String, dynamic> json) => _$LedgerSummaryFromJson(json); } // 其他Freezed类同样实现BaseModel滚动视图控制器可以接受
List<BaseModel>作为数据源,通过is关键字判断具体类型:if (item is LedgerSummary) { // 渲染LedgerSummary对应的UI组件 } else if (item is OtherModel) { // 渲染OtherModel对应的UI组件 }密封类+when方法匹配
如果所有模型属于同一业务体系,可以用Freezed的密封类特性,通过when方法做类型匹配:@freezed sealed class AppModel with _$AppModel { const factory AppModel.ledgerSummary({required int ledgerId}) = LedgerSummary; const factory AppModel.userInfo({required String name}) = UserInfo; factory AppModel.fromJson(Map<String, dynamic> json) => _$AppModelFromJson(json); } // 使用时直接通过when分发UI item.when( ledgerSummary: (ledgerId) => LedgerSummaryWidget(ledgerId: ledgerId), userInfo: (name) => UserInfoWidget(name: name), );依赖类型检查而非runtimeType
无需纠结runtimeType的字符串值,代码中用is关键字做类型判断足够可靠:print(ledgerSummaryAgain is LedgerSummary); // 输出true
内容的提问来源于stack exchange,提问作者Pavel Murnikov
相关产品推荐
相关产品推荐

