Flutter页面重载出现RangeError(index)错误求助
问题解决:Flutter页面加载时的RangeError及加载状态处理
错误根源
你遇到的RangeError (index): Invalid value: Only valid value is 0: 1,是因为页面初始化时time变量为空字符串,执行time.split("T")后得到的列表只有1个元素(空字符串),但你直接尝试访问索引1,导致数组越界。这个错误会在数据加载完成后消失,因为此时time已经被赋值为有效的时间字符串。
解决方案
我们可以通过添加加载状态标记,配合安全的字符串处理来解决这个问题:
- 添加加载状态变量:用于控制加载指示器和页面内容的显示切换
- 安全处理字符串拆分:避免空字符串或格式异常导致的索引错误
- 更新异步请求逻辑:请求完成后更新加载状态
以下是修改后的完整代码:
import 'dart:async'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:space_flight_recorder/nav_bar/Nav_Drawer.dart'; import 'dart:convert'; import 'package:space_flight_recorder/nav_bar/bottom_nav_bar.dart'; class MyHome extends StatefulWidget { const MyHome({Key? key}) : super(key: key); @override _MyHomeState createState() => _MyHomeState(); } class _MyHomeState extends State<MyHome> { DateTime launchTime = DateTime.now(); String Name=''; String description=''; String agencyName=''; String type = ''; String rocketName=''; String rocketVariant=''; String missionName=''; String orbitName=''; String location=''; String time=''; String date = ''; // 添加加载状态标记 bool isLoading = true; @override void initState() { super.initState(); fetchMyHome(); Timer.periodic(Duration(seconds: 1), (Timer t) => updateCountdown()); } void fetchMyHome() async { final response = await http.get( Uri.parse('https://lldev.thespacedevs.com/2.2.0/launch/upcoming/') ); // 请求完成后更新加载状态 setState(() { isLoading = false; }); if (response.statusCode == 200) { final data = jsonDecode(response.body); final List<dynamic> results = data['results']; if (results.isNotEmpty) { final launch = results.elementAt(0); final launchTimeStr = launch['net']; launchTime = DateTime.parse(launchTimeStr).toLocal(); final Launchname = launch['name']; Name = Launchname.toString(); final descp = launch['mission']['description']; description=descp; final agenName=launch['launch_service_provider']['name']; agencyName=agenName; final typee=launch['launch_service_provider']['type']; type=typee; final r_name=launch['rocket']['configuration']['name']; rocketName=r_name; final r_variant=launch['rocket']['configuration']['variant']; rocketVariant=r_variant; final m_name=launch['mission']['name']; missionName=m_name; final orbit_name=launch['mission']['orbit']['name']; orbitName=orbit_name; final pad_location=launch['pad']['location']['name']; location=pad_location; final estimated_time=launch['net']; time=estimated_time; setState(() {}); } else { print('No upcoming launches found'); } } else { print('Failed to fetch upcoming launches: ${response.statusCode}'); } } void updateCountdown() { setState(() {}); } @override Widget build(BuildContext context) { final now = DateTime.now().toLocal(); final duration = launchTime.difference(now); final days = duration.inDays; final hours = duration.inHours.remainder(24); final minutes = duration.inMinutes.remainder(60); final seconds = duration.inSeconds.remainder(60); // 安全处理时间字符串拆分 String date_final = ''; String time_final = ''; if (time.isNotEmpty) { final final_time = time.split("T"); date_final = final_time.isNotEmpty ? final_time[0] : ''; time_final = final_time.length > 1 ? final_time[1] : ''; } return Scaffold( backgroundColor: Colors.black54, drawer: Nav_Drawer(), appBar: AppBar( backgroundColor: Colors.black, title: const Text('Welcome'), ), // 根据加载状态切换显示内容 body: isLoading ? Center(child: CircularProgressIndicator(color: Colors.white)) : SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ const SizedBox(height: 20), Text( 'Next Launch in:', style: TextStyle( color: Colors.white, fontSize: 24), ), const SizedBox(height: 20), Stack( alignment: Alignment.center, children: [ CarouselSlider( items: [ Image.network('https://c4.wallpaperflare.com/wallpaper/559/511/583/spacex-rocket-falcon-9-smoke-wallpaper-preview.jpg'), Image.network('https://c4.wallpaperflare.com/wallpaper/81/233/257/spacex-rocket-smoke-cape-canaveral-wallpaper-preview.jpg'), Image.network('https://c4.wallpaperflare.com/wallpaper/758/798/536/spacex-rocket-launch-pads-falcon-heavy-wallpaper-preview.jpg'), Image.network('https://cdnn1.img.sputniknews.com/img/07e6/0a/17/1102543952_0:0:3071:1728_1920x0_80_0_0_94bf3eb33e85402d96a49a4e84e93b84.jpg'), Image.network('https://static.theprint.in/wp-content/uploads/2018/03/6-01-e1530068959485.jpg?compress=true&quality=80&w=376&dpr=2.6'), Image.network('https://c4.wallpaperflare.com/wallpaper/390/31/781/spacex-rocket-falcon-9-wallpaper-preview.jpg'), ], options: CarouselOptions( height: 300, autoPlay: false, enableInfiniteScroll: true, autoPlayAnimationDuration: Duration(seconds: 3), viewportFraction: 1, ), ), Column( children: [ Text( '$days : $hours : $minutes : $seconds', style: TextStyle( fontSize: 30, color: Colors.white ), ), Text( 'Days : Hours : Minutes : Seconds', style: TextStyle( color: Colors.white, fontSize: 12 ), ), ], ), ], ), Text(Name, style: TextStyle( color: Colors.white, fontSize: 20 ), ), SizedBox(height: 20), Padding( padding: EdgeInsets.all(10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Divider( color: Colors.white, ), Text('Description:', style: TextStyle( color: Colors.blueAccent, fontSize: 14 ), ), SizedBox(height: 4), Text(description, style: TextStyle( color: Colors.white, fontSize: 14 ),), Divider( color: Colors.white, ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Agency:', style: TextStyle( color: Colors.blueAccent, ), ), Text(agencyName, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Launch type:', style: TextStyle( color: Colors.blueAccent, ), ), Text(type, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Rocket name:', style: TextStyle( color: Colors.blueAccent, ), ), Text(rocketName, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Rocket variant:', style: TextStyle( color: Colors.blueAccent, ), ), Text(rocketVariant, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Mission Name:', style: TextStyle( color: Colors.blueAccent, ), ), Text(missionName, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Orbit:', style: TextStyle( color: Colors.blueAccent, ), ), Text(orbitName, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Launch Location:', style: TextStyle( color: Colors.blueAccent, ), ), ], ), Row( mainAxisAlignment: MainAxisAlignment.end, children:[ Text(location, style: TextStyle( color: Colors.white ), ), Divider( color: Colors.white, ) ], ), Divider( color: Colors.white, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Date:', style: TextStyle( color: Colors.blueAccent, ), ), Text(date_final, style: TextStyle( color: Colors.white ), ), ], ), Divider( color: Colors.white, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Time:', style: TextStyle( color: Colors.blueAccent, ), ), Text(time_final, style: TextStyle( color: Colors.white ), ), ], ), ], ), ), ], ), ), bottomNavigationBar: BottomNavBar(0), ); } }
关键修改点说明
- 加载状态变量
isLoading:初始化为true,请求完成后设为false,控制页面显示加载指示器或实际内容 - 安全拆分时间字符串:先判断
time是否为空,再拆分并检查数组长度,避免索引越界 - 加载指示器:在
isLoading为true时显示居中的白色圆形加载指示器,提升用户体验
内容的提问来源于stack exchange,提问作者Siddh Purohit
相关产品推荐
相关产品推荐

