Flutter:异步任务在“initState()”中无法按预期工作

Posted

技术标签:

【中文标题】Flutter:异步任务在“initState()”中无法按预期工作【英文标题】:Flutter: Async task do not work as expected in "initState()" 【发布时间】:2019-08-29 07:15:57 【问题描述】:

我正在尝试使用从 REST API 获得的数据在我的颤振应用程序中填充 DropDownMenu。以下是我获取数据的方式。

     class _CreateSellingAdvertisementState extends State<CreateSellingAdvertisement> 

      List<String> categoryList = List<String>();
      List<String> productList = List<String>();
      List<String> productUnitList = List<String>();

      @override
      void initState() 
        super.initState();

        //Load category List
        DataFetch()
            .fetchCategoryList(
                AppNavigation.getAPIUrl() +
                    "productCategory/getAllProductCategories",
                ProductCategory)
            .then((onValue) 

              List<String> listString = new List<String>();

          for (int i = 0; i < onValue.length; i++) 
            listString.add(onValue[i].categoryName);
          

          setState(() 
           categoryList = listString; 
          );
        );

print(categoryList);
...........................
    

当我打印上面的categoryList 时,它始终是[]。但是我使用FutureBuilder 使用了相同的方法,并且效果很好。

下面是DataFetch().fetchCategoryList方法

 Future<List<ProductCategory>> fetchCategoryList(
      String url, Object obj) async 
    final response = await http.get(url);
    // Use the compute function to run parsePhotos in a separate isolate
    return parseCategoryDataList(response.body);
  

  List<ProductCategory> parseCategoryDataList(String responseBody) 
    final parsed =
        convert.json.decode(responseBody).cast<Map<String, dynamic>>();

    List<ProductCategory> list = parsed
        .map<ProductCategory>((json) => new ProductCategory.fromJson(json))
        .toList();
    return list;
  

下面是我的下拉列表代码

Widget _buildDropDown(List<String> list) 
    return new DropdownButton<String>(
      items: list.map((String value) 
        return new DropdownMenuItem<String>(
          value: value,
          child: new Text(value),
        );
      ).toList(),
      value: "A",
      isExpanded: true,
      onChanged: (_) ,
    );
  

下拉列表总是抛出以下异常

I/flutter (21217): The following assertion was thrown building CreateSellingAdvertisement(dirty, state:
I/flutter (21217): _CreateSellingAdvertisementState#1a80a):
I/flutter (21217): 'package:flutter/src/material/dropdown.dart': Failed assertion: line 560 pos 15: 'items == null ||
I/flutter (21217): items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) => item.value ==
I/flutter (21217): value).length == 1': is not true.
I/flutter (21217): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter (21217): more information in this error message to help you determine and fix the underlying cause.
I/flutter (21217): In either case, please report this assertion by filing a bug on GitHub:
I/flutter (21217):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter (21217): When the exception was thrown, this was the stack:
I/flutter (21217): #2      new DropdownButton 
I/flutter (21217): #3      _CreateSellingAdvertisementState._buildDropDown
I/flutter (21217): #4      _CreateSellingAdvertisementState.build
I/flutter (21217): #5      StatefulElement.build 
I/flutter (21217): #6      ComponentElement.performRebuild 
I/flutter (21217): #7      Element.rebuild 
I/flutter (21217): #8      BuildOwner.buildScope 
I/flutter (21217): #9      _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame 
I/flutter (21217): #10     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback 
I/flutter (21217): #11     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback 
I/flutter (21217): #12     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame 
I/flutter (21217): #13     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame 
I/flutter (21217): #17     _invoke (dart:ui/hooks.dart:209:10)
I/flutter (21217): #18     _drawFrame (dart:ui/hooks.dart:168:3)
I/flutter (21217): (elided 5 frames from class _AssertionError and package dart:async)

这是为什么?

【问题讨论】:

你能不能尝试在setState 之后在.then 中打印categoryList 并检查 【参考方案1】:

Future 方法在initState 内部有效,这里的问题似乎是由于列表未按预期更新所致。将项目添加到 List 时,for 循环最好放在 setState() 内,最好将项目直接添加到 categoryList

setState(()
  for (int i = 0; i < onValue.length; i++)   
    categoryList.add(onValue[i].categoryName);  
  
);

在 for 循环中调用 setState() 也应该类似地工作。

for (int i = 0; i < onValue.length; i++)   
  setState(() 
    categoryList.add(onValue[i].categoryName);  
  

【讨论】:

以上是关于Flutter:异步任务在“initState()”中无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

如何测试 initState() 中有异步调用的 Flutter 应用程序?

颤振异步调用不会在 initState() 中异步运行

Flutter应用打开时如何从sqlite数据库加载初始状态数据

FLutter入门:异步加载组件FutureBuilder

Flutter 在 initState 方法中获取上下文

屏幕initState上的Flutter Snackbar