You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter JSON解析问题:页面无数据展示求助

解决方案

1. 定义对应JSON结构的数据模型类

首先需要创建匹配JSON结构的Dart模型,确保能正确解析嵌套的数组与对象:

// 通用标签项模型(适配multiDeviceSupport、mainFeatures、benefits的子项)
class FeatureItem {
  final String label;

  FeatureItem({required this.label});

  factory FeatureItem.fromJson(Map<String, dynamic> json) {
    return FeatureItem(
      label: json['label'] ?? '',
    );
  }
}

// App详情核心模型
class AppDetails {
  final String systemOverview;
  final List<FeatureItem> multiDeviceSupport;
  final List<FeatureItem> mainFeatures;
  final List<FeatureItem> benefits;

  AppDetails({
    required this.systemOverview,
    required this.multiDeviceSupport,
    required this.mainFeatures,
    required this.benefits,
  });

  factory AppDetails.fromJson(Map<String, dynamic> json) {
    return AppDetails(
      systemOverview: json['systemOverview'] ?? '',
      multiDeviceSupport: (json['multiDeviceSupport'] as List)
          .map((item) => FeatureItem.fromJson(item))
          .toList(),
      mainFeatures: (json['mainFeatures'] as List)
          .map((item) => FeatureItem.fromJson(item))
          .toList(),
      benefits: (json['benefits'] as List)
          .map((item) => FeatureItem.fromJson(item))
          .toList(),
    );
  }
}

// 顶层App信息模型
class AppInfo {
  final String name;
  final String category;
  final String subcategory;
  final String description;
  final List<AppDetails> appDetails;

  AppInfo({
    required this.name,
    required this.category,
    required this.subcategory,
    required this.description,
    required this.appDetails,
  });

  factory AppInfo.fromJson(Map<String, dynamic> json) {
    return AppInfo(
      name: json['name'] ?? '',
      category: json['category'] ?? '',
      subcategory: json['subcategory'] ?? '',
      description: json['description'] ?? '',
      appDetails: (json['appDetails'] as List)
          .map((item) => AppDetails.fromJson(item))
          .toList(),
    );
  }
}

2. 修复TestScreen页面:添加数据加载与正确UI展示

原代码核心问题是无数据加载逻辑且UI布局错误,以下是完整修复后的代码:

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

class TestScreen extends StatefulWidget {
  const TestScreen({Key? key}) : super(key: key);

  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  AppInfo? appInfo;

  @override
  void initState() {
    super.initState();
    _loadAndParseJson();
  }

  // 加载并解析JSON数据(模拟本地字符串,实际可替换为网络/asset加载)
  void _loadAndParseJson() {
    final jsonString = '''
    {
      "name": "TestingApp",
      "category": "Production",
      "subcategory": "Productivity",
      "imageUrl": "Testing-Banner.jpg",
      "logo": "PI.png",
      "description": "Testing is an application for easy & effective Inspection",
      "appDetails": [{
          "systemOverview": "https:url.com",
          "multiDeviceSupport": [{
                  "label": "Multi-Device"
              },
              {
                  "label": "Multi-Lingual"
              },
              {
                  "label": "Multi-Database"
              }
          ],
          "mainFeatures": [{
                  "label": "Testing"
              },
              {
                  "label": "Ease"
              },
              {
                  "label": "Select failure "
              },
              {
                  "label": "Add comments & take evidence Pictures"
              },
              {
                  "label": "Send  results to central system"
              },
              {
                  "label": "Search/view "
              }
          ],
          "benefits": [{
                  "label": "Easy & quick solution "
              },
              {
                  "label": "Go paperless "
              },
              {
                  "label": "Lower costs"
              },
              {
                  "label": "Improve quality/safety"
              },
              {
                  "label": "Configurable on hand-held devices and tablets"
              },
              {
                  "label": "Electronic notifications to corresponding personnel’s"
              }
          ]
      }]
    }
    ''';

    final jsonData = jsonDecode(jsonString);
    setState(() {
      appInfo = AppInfo.fromJson(jsonData);
    });
  }

  // 通用模块展示组件:标题+列表项
  Widget buildSection(String title, List<FeatureItem> items) {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(
            color: Colors.grey.withOpacity(0.2),
            blurRadius: 4,
            offset: const Offset(0, 2),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 12),
          Column(
            children: items.map((item) {
              return Padding(
                padding: const EdgeInsets.symmetric(vertical: 4),
                child: Row(
                  children: [
                    const Icon(Icons.check_circle, color: Colors.green, size: 18),
                    const SizedBox(width: 8),
                    Expanded(child: Text(item.label)),
                  ],
                ),
              );
            }).toList(),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.grey[100], // 替换为你的kBackgroundColor
        title: const Text(
          'Home',
          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
        ),
      ),
      body: appInfo == null
          ? const Center(child: CircularProgressIndicator())
          : SingleChildScrollView(
              padding: const EdgeInsets.symmetric(vertical: 16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // 展示App基础信息
                  Padding(
                    padding: const EdgeInsets.symmetric(horizontal: 16),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          appInfo!.name,
                          style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                        ),
                        const SizedBox(height: 8),
                        Text('${appInfo!.category} > ${appInfo!.subcategory}'),
                        const SizedBox(height: 12),
                        Text(appInfo!.description),
                      ],
                    ),
                  ),
                  const SizedBox(height: 20),
                  // 展示各个详情模块
                  if (appInfo!.appDetails.isNotEmpty)
                    ...[
                      buildSection('Multi Device Support', appInfo!.appDetails[0].multiDeviceSupport),
                      buildSection('Main Features', appInfo!.appDetails[0].mainFeatures),
                      buildSection('Benefits', appInfo!.appDetails[0].benefits),
                      // 展示系统概览
                      Container(
                        margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
                        padding: const EdgeInsets.all(16),
                        decoration: BoxDecoration(
                          color: Colors.white,
                          borderRadius: BorderRadius.circular(8),
                          boxShadow: [
                            BoxShadow(
                              color: Colors.grey.withOpacity(0.2),
                              blurRadius: 4,
                              offset: const Offset(0, 2),
                            ),
                          ],
                        ),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const Text(
                              'System Overview',
                              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 12),
                            Text(appInfo!.appDetails[0].systemOverview),
                          ],
                        ),
                      ),
                    ],
                ],
              ),
            ),
    );
  }
}

3. 关键问题修复点

  • 缺失数据加载:原代码details列表始终为空,新增_loadAndParseJson方法在页面初始化时解析JSON并更新状态。
  • UI布局错误:Scaffold的body直接使用Expanded无效,改为SingleChildScrollView包裹Column,确保内容可滚动且布局合法。
  • 模型类缺失:没有对应JSON结构的模型导致无法解析嵌套数据,新增三个模型类实现JSON到Dart对象的转换。
  • 展示逻辑错误:原代码直接打印对象无法展示列表内容,新增通用buildSection组件,将每个模块的标题与列表项清晰展示。

4. 扩展建议

  • 若JSON来自网络,可将_loadAndParseJson中的字符串替换为http包的网络请求逻辑。
  • 若JSON来自本地asset,需在pubspec.yaml中配置asset路径,使用rootBundle.loadString加载。
  • 可根据需求调整buildSection的样式,比如修改容器颜色、图标、间距等。

内容的提问来源于stack exchange,提问作者talal habib

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:06:13