如何修复调用 API 时卡住的颤振应用程序(仅限发布版本)

Posted

技术标签:

【中文标题】如何修复调用 API 时卡住的颤振应用程序(仅限发布版本)【英文标题】:How to fix flutter app stuck in loading when calling API (only Release Version) 【发布时间】:2020-09-07 04:00:21 【问题描述】:

我正在为 Covid-19 构建应用程序。 在构建应用程序时,我通过函数调用 API,并且希望仅在成功命中 API 后加载内容。

在调试模式下,一切正常,从 api 获取数据后加载内容,直到显示加载屏幕,但处于发布模式,但卡在加载屏幕。这是示例代码

import 'package:covid_19/widgets/counter.dart';
import 'package:covid_19/widgets/my_header.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:covid_19/API/api.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'constant.dart';

class HomeScreen extends StatefulWidget 
  @override
  _HomeScreenState createState() => _HomeScreenState();


class _HomeScreenState extends State<HomeScreen> 
  final controller = ScrollController();
  double offset = 0;
  String countryname="All";
  bool loaded=false;
  List country=[];
  String totalcase="0";
  String infectedcase="0";
  String deathcase="0";
  String recoveredcase="0";
  String newcase="0";
  String activecase="0";
  String criticalcase="0";
  String newdeathcase="0";
  String testtotal="0";
  String day="";
  String time="";
  List stat=[];

  Future getcountry() async
    final data=await getcountries.getdata();
    setState(() 
      country=data;
    );
    getstatss();
  
  Future getstatss() async
    final data=await getstats.getdata();
    setState(() 
      stat=data;
    );
    for(int i=0;i<stat.length;i++)
      if(countryname==stat[i]['country'])
        setState(() 
          totalcase=stat[i]['cases']['total'].toString();
          recoveredcase=stat[i]['cases']['recovered'].toString();
          newcase=stat[i]['cases']['new'].toString();
          activecase=stat[i]['cases']['active'].toString();
          criticalcase=stat[i]['cases']['critical'].toString();
          newdeathcase=stat[i]['deaths']['new'].toString();
          deathcase=stat[i]['deaths']['total'].toString();
          testtotal=stat[i]['tests']['total'].toString();
          day=stat[i]['day'].toString();
          time=stat[i]['time'].toString();
        );
        break;
      
    
    setState(() 
      loaded=true;
    );
  


  Future filterdata() async
    totalcase="0";
    infectedcase="0";
    deathcase="0";
    recoveredcase="0";
    newcase="0";
    activecase="0";
    criticalcase="0";
    newdeathcase="0";
    testtotal="0";
    day="";
    time="";
    setState(() 
      loaded=false;
    );
    for(int i=0;i<stat.length;i++)
      print(stat[i]);
      if(countryname==stat[i]['country'])
        print(countryname);
        totalcase=stat[i]['cases']['total'].toString();
        recoveredcase=stat[i]['cases']['recovered'].toString();
        newcase=stat[i]['cases']['new'].toString();
        activecase=stat[i]['cases']['active'].toString();
        criticalcase=stat[i]['cases']['critical'].toString();
        newdeathcase=stat[i]['deaths']['new'].toString();
        deathcase=stat[i]['deaths']['total'].toString();
        testtotal=stat[i]['tests']['total'].toString();
        day=stat[i]['day'].toString();
        time=stat[i]['time'].toString();
      
    
    setState(() 
      loaded=true;
    );

  

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    getcountry();

  


  @override
  Widget build(BuildContext context) 
    return WillPopScope(
      onWillPop: () async => false,
      child: MaterialApp(
        title: "Covid 19",
        theme: new ThemeData(
          primaryColor: Colors.blue,
          primaryColorLight: Color.fromRGBO(111, 196, 242, 1),
        ),
        darkTheme: ThemeData(
          brightness: Brightness.dark,
        ),
        home: Scaffold(
          body: SingleChildScrollView(
              controller: controller,
              child:Column(
                children: <Widget>[
                  MyHeader(
                    image: "assets/icons/Drcorona.svg",
                    textTop: "You just Need",
                    textBottom: "to stay at home.",
                    offset: offset,
                  ),
                  loaded?Container(
                    margin: EdgeInsets.symmetric(horizontal: 20),
                    padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
                    height: 60,
                    width: double.infinity,
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(25),
                      border: Border.all(
                        color: Color(0xFFE5E5E5),
                      ),
                    ),
                    child: Row(
                      children: <Widget>[
                        SvgPicture.asset("assets/icons/maps-and-flags.svg"),
                        SizedBox(width: 20),
                        Expanded(
                          child: DropdownButton(
                            isExpanded: true,
                            underline: SizedBox(),
                            icon: SvgPicture.asset("assets/icons/dropdown.svg"),
                            value: countryname,
                            items: country.map<DropdownMenuItem<dynamic>>((dynamic value) 
                              return DropdownMenuItem<String>(
                                value: value,
                                child: Text(value),
                              );
                            ).toList(),
                            onChanged: (value) 
                              setState(() 
                                countryname=value;
                              );
                              filterdata();

                            ,
                          ),
                        ),
                      ],
                    ),
                  ):SizedBox(),
                  SizedBox(height: 20),
                  loaded?Padding(
                    padding: EdgeInsets.symmetric(horizontal: 20),
                    child: Column(
                      children: <Widget>[
                        Row(
                          children: <Widget>[
                            RichText(
                              text: TextSpan(
                                children: [
                                  TextSpan(
                                    text: "Case Update\n",
                                    style: kTitleTextstyle,
                                  ),
                                  TextSpan(
                                    text: time!=null||time==""?"Newest update $time.split("T")[0] $time.split("T")[1].split("+")[0]":"Todays Update",
                                    style: TextStyle(
                                      color: kTextLightColor,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                            Spacer(),
                            Text(
                              "See details",
                              style: TextStyle(
                                color: kPrimaryColor,
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                          ],
                        ),
                        SizedBox(height: 20),
                        Container(
                          padding: EdgeInsets.all(20),
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(20),
                            color: Colors.white,
                            boxShadow: [
                              BoxShadow(
                                offset: Offset(0, 4),
                                blurRadius: 30,
                                color: kShadowColor,
                              ),
                            ],
                          ),
                          child: Column(
                            children: <Widget>[
                              Row(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  Counter(
                                    color: kInfectedColor,
                                    sizeup:1.5,
                                    number: totalcase=="null"?int.parse("0"):int.parse(totalcase),
                                    title: "Total Cases",
                                  ),

                                ],
                              ),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                children: <Widget>[
                                  Counter(
                                    color: kInfectedColor,
                                    number: activecase=="null"?int.parse("0"):int.parse(activecase),
                                    sizeup: 1.2,
                                    title: "Infected",
                                  ),
                                  Counter(
                                    color: kDeathColor,
                                    number: deathcase=="null"?int.parse("0"):int.parse(deathcase),
                                    sizeup: 1.2,
                                    title: "Deaths",
                                  ),
                                  Counter(
                                    color: kRecovercolor,
                                    number: recoveredcase=="null"?int.parse("0"):int.parse(recoveredcase),
                                    sizeup: 1.2,
                                    title: "Recovered",
                                  ),
                                ],
                              ),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                                children: <Widget>[
                                  Counter(
                                    color: kInfectedColor,
                                    number: newcase=="null"?int.parse("0"):int.parse(newcase),
                                    sizeup: 1,
                                    title: "New Case",
                                  ),
                                  Counter(
                                    color: kDeathColor,
                                    number: newdeathcase=="null"?int.parse("0"):int.parse(newdeathcase),
                                    sizeup: 1,
                                    title: "New Death",
                                  ),
                                  Counter(
                                    color: kRecovercolor,
                                    number: testtotal=="null"?int.parse("0"):int.parse(testtotal),
                                    sizeup: 1,
                                    title: "Total Tests",
                                  ),
                                ],
                              ),
                            ],
                          ),
                        ),
                        SizedBox(height: 20),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: <Widget>[
                            Text(
                              "Spread of Virus",
                              style: kTitleTextstyle,
                            ),
                            Text(
                              "See details",
                              style: TextStyle(
                                color: kPrimaryColor,
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                          ],
                        ),
                        Container(
                          margin: EdgeInsets.only(top: 20),
                          padding: EdgeInsets.all(20),
                          height: 178,
                          width: double.infinity,
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(20),
                            color: Colors.white,
                            boxShadow: [
                              BoxShadow(
                                offset: Offset(0, 10),
                                blurRadius: 30,
                                color: kShadowColor,
                              ),
                            ],
                          ),
                          child: Image.asset(
                            "assets/images/map.png",
                            fit: BoxFit.contain,
                          ),
                        ),
                      ],
                    ),
                  ):Center(child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      CircularProgressIndicator(),
                      Text("Connecting",style: TextStyle(fontSize: 20),),
                      SizedBox(height: 50,),
                    ],

                  ),),
                ],
              )),

        ),
      ),
    );
  

【问题讨论】:

您不应该在 setState 方法上使用任何 逻辑。顾名思义,它应该只为一个新状态改变状态,而不是解析那个或任何东西。尝试将您的 for 循环移到 setState 之外,并且只在其上设置 loaded = true 试过了,还是有同样的问题,我会更新问题中的编辑代码。 您将loaded = true 设置在多个位置。我会将您的解析逻辑提取到数据模型中,因为它会使整个小部件变得臃肿和混乱。 这是造成问题的原因吗?我是新手,如果是,我该如何解决? 【参考方案1】:

我很确定问题出在这段代码中。 添加一些 != null 检查或在 min try-catch 时添加一些可能是个好主意 :)

if(countryname==stat[i]['country'])
        print(countryname);
        totalcase=stat[i]['cases']['total'].toString();
        recoveredcase=stat[i]['cases']['recovered'].toString();
        newcase=stat[i]['cases']['new'].toString();
        activecase=stat[i]['cases']['active'].toString();
        criticalcase=stat[i]['cases']['critical'].toString();
        newdeathcase=stat[i]['deaths']['new'].toString();
        deathcase=stat[i]['deaths']['total'].toString();
        testtotal=stat[i]['tests']['total'].toString();
        day=stat[i]['day'].toString();
        time=stat[i]['time'].toString();
      

【讨论】:

以上是关于如何修复调用 API 时卡住的颤振应用程序(仅限发布版本)的主要内容,如果未能解决你的问题,请参考以下文章

如何修复解决依赖关系...使用颤振运行时出错?

双击按钮时如何修复颤振中的多个导航

如何修复颤振中的“回复已提交的错误”?

React Native api 调用不会在远程调试模式之外发生(仅限 iOS)

如何修复 Fetch API 中的 CORS 问题

数据不会在颤振中从 API 加载。我该如何解决?