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

如何通过Dio调用API并结合Provider展示旅游地点数据?

解决Dio+Provider获取并展示旅游地点数据的问题

现有代码的核心问题

  1. 类型不匹配:Provider中_wisata定义为List<ListWisata>,但实际API返回的datawisata是List<Datawisata>,类型完全错误
  2. 不安全的空值访问:直接用c!.datawisata!会导致空指针异常,未处理API请求失败或数据为空的情况
  3. 错误处理缺失:API请求的catch块仅执行(e.toString()),无实际错误日志输出
  4. UI数据访问错误:wisatalist[index]实际是Datawisata对象,需对应访问其属性

步骤1:修正API请求代码

import 'package:dio/dio.dart';

class WisataApi {
  // 复用Dio实例,避免重复创建
  static final Dio _dio = Dio();

  static Future<ListWisata?> getWisata() async {
    try {
      final result = await _dio.get('https://windramayu-api-default-rtdb.asia-southeast1.firebasedatabase.app/');
      print('getWisata: ${result.data}');
      return ListWisata.fromJson(result.data);
    } catch (e) {
      // 打印错误日志,方便调试
      print('API请求失败: ${e.toString()}');
      return null;
    }
  }
}

步骤2:修正Provider状态管理类

import 'package:flutter/foundation.dart';
import 'your_model_file_path.dart'; // 替换为你的ListWisata/Datawisata模型文件路径

class HomeViewModel extends ChangeNotifier {
  // 正确定义为Datawisata列表
  List<Datawisata> _wisata = [];
  // 返回不可变列表,防止外部直接修改
  List<Datawisata> get wisatalist => List.unmodifiable(_wisata);

  Future<void> getWisatas() async {
    final response = await WisataApi.getWisata();
    if (response?.datawisata != null) {
      _wisata = response!.datawisata!;
      notifyListeners(); // 通知UI更新
    } else {
      // 数据为空时清空列表,避免旧数据残留
      _wisata = [];
      notifyListeners();
    }
  }
}

步骤3:修正UI展示代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'your_viewmodel_file_path.dart'; // 替换为HomeViewModel文件路径

class WisataListScreen extends StatefulWidget {
  const WisataListScreen({super.key});

  @override
  State<WisataListScreen> createState() => _WisataListScreenState();
}

class _WisataListScreenState extends State<WisataListScreen> {
  @override
  void initState() {
    super.initState();
    // 页面初始化时调用API获取数据
    Provider.of<HomeViewModel>(context, listen: false).getWisatas();
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<HomeViewModel>(
      builder: (context, modelView, child) {
        return ListView.builder(
          itemCount: modelView.wisatalist.length,
          scrollDirection: Axis.horizontal,
          itemBuilder: (context, index) {
            final wisata = modelView.wisatalist[index];
            return Card(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    // 确保Datawisata类中有nama字段
                    Text(wisata.nama ?? '无名称'),
                    Text(wisata.alamat ?? '无地址'),
                    Text(wisata.about ?? '无介绍'),
                  ],
                ),
              ),
            );
          },
        );
      },
    );
  }
}

步骤4:在main.dart中注册Provider

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => HomeViewModel(),
      child: MaterialApp(
        title: '旅游地点列表',
        home: const WisataListScreen(),
      ),
    );
  }
}

额外注意事项

  • 确保Datawisata类中包含nama字段(根据UI代码中的wisatalist[index].nama),如果quicktype生成时遗漏,需手动添加
  • 若API返回的datawisata是Map而非数组,需调整模型类和解析逻辑(但根据你提供的JSON结构是数组,当前模型是正确的)
  • 可添加加载状态(比如在ViewModel中增加isLoading字段),提升UI体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 11:40:33