Flutter用StreamBuilder拉取API时报Future<dynamic>非Stream<List<dynamic>>子类型错误
错误原因
你给StreamBuilder的stream参数传入了Backend.getData(),但该方法是async修饰的异步方法,返回值类型为Future,不是Stream,类型不匹配所以抛出该错误。
同时你的代码逻辑存在冗余:你已经在initState中提前请求了接口数据存入_welcome变量,也做了加载状态判断,完全不需要额外嵌套StreamBuilder。
方案1:直接使用已请求的本地数据(改动最小)
直接删掉多余的StreamBuilder层,用已经拿到的_welcome渲染列表即可,修改Search_product.dart中waiting为false时的代码:
: Expanded( child: ListView.builder( padding: EdgeInsets.all(8), itemCount: _welcome.length, itemBuilder: (BuildContext context, int index) { Welcome item = _welcome[index]; return Card( child: Column( children: <Widget>[ ListTile( leading: CircleAvatar( radius: 30, backgroundImage: NetworkImage(item.image), ), title: Text(item.title), subtitle: Text(item.description), trailing: Text(item.price.toString()), ) ], ), ); }), )
方案2:若确实需要使用StreamBuilder
首先需要把Future类型的返回值转成Stream,你可以直接调用Future的asStream()方法,同时调整逻辑删掉initState里的冗余请求:
- 先修改
Backend.dart中getData的返回值类型声明,避免隐式dynamic问题:
static Future<List<Welcome>> getData() async { try { var url = Uri.parse('https://fakestoreapi.com/products'); var response = await http.get(url); if (response.statusCode == 200) { return welcomeFromJson(response.body); } else { throw Exception('接口请求失败'); } } catch (e) { rethrow; } }
- 修改
Search_product.dart的代码,去掉initState里的请求,直接用StreamBuilder处理加载、错误、渲染逻辑:
// 删掉原来的_welcome、waiting变量,修改build里的容器部分 Container( child: Expanded( child: StreamBuilder<List<Welcome>>( stream: Backend.getData().asStream(), builder: (BuildContext context, AsyncSnapshot<List<Welcome>> snapshot) { // 加载状态 if (snapshot.connectionState == ConnectionState.waiting) { return Center( child: SizedBox( width: 50, height: 50, child: CircularProgressIndicator(), ), ); } // 错误状态 if (snapshot.hasError) { return Center(child: Text('加载失败:${snapshot.error}')); } // 渲染数据 List<Welcome> list = snapshot.data!; return ListView.builder( padding: EdgeInsets.all(8), itemCount: list.length, itemBuilder: (BuildContext context, int index) { Welcome item = list[index]; return Card( child: Column( children: <Widget>[ ListTile( leading: CircleAvatar( radius: 30, backgroundImage: NetworkImage(item.image), ), title: Text(item.title), subtitle: Text(item.description), trailing: Text(item.price.toString()), ) ], ), ); }); }), ), )
额外注意
你原来的代码里写了snapshot.data[index].welcome.image是错误写法,接口返回的列表元素本身就是Welcome类型对象,不需要额外加.welcome调用属性。
内容的提问来源于stack exchange,提问作者Vishakha Dikshit
相关产品推荐
相关产品推荐

