为找出问题,我创建了新代码,新程序和新计算机。 结果相同,只是不希望打印“引号后具有” anythingPrice”之后的任何值
同样,我可以给您一个临时键,您可以完全运行代码。在你身边。
请让我知道。
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
//import 'package:flutter_web/material.dart';
//import 'package:flutter/main.dart' as app;
//import 'package:flutter_web_ui/ui.dart' as ui;
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
// await client.get('https://cloud.iexapis.com/stable/stock/market/batch?symbols=CNPF,ICOL,PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,IEI,TLH,DIA,BSJF,MONY&types=quote,stats&token=');
await client.get('https://cloud.iexapis.com/stable/stock/market/batch?symbols=PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,PGF,SNLN,DVHL,AUNZ,MDIV,PHB,PFXF,FPE,TIPX,MLN,SDIV,SIPE,SEMF,EMAG,IEMF,EU,BSCM,LEMF,BSCL,BSCK,BSCJ,BSCI,DSUM,BSCF,KBWD,PCEF,BSCG,BSCH,HYEM,ITM,BKLN,PGHY,IBCE,PZT,IJNK,XMPT,THHY,QYLD,IHY,IYLD,SHYD,PRB,DVHI,GOVT,BSJJ,BSJK,RIGS,INY,IBCD,PZA,PFIG,IBCC,BSCE,PVI,MBG,CXA,FWDB,DIV,CHLC,BSJI,FLTR,PWZ,MUAH,IBDD,PICB,IBDB,BSJH,RVNU,BSJG,IBDC,XOVR,BSJE,EBND,PCY,BWX,SJNK,DES,ANGL,BAB,SST,EMCD,CBND,HYD,PLW,SCPB,FLRN,BWZ,KBWY,ELD,IBND,AOK,RWXL,ITR,DON,DGRS,JNK,TZD,EPU,PFF,HYLD,GGOV,ULST,SPHD,HFIN,DGRW,LWC,ALD,LEMB,AGND,ITIP,EMHY,QLTC,TFI,SRLN,HYLS,SHM,GNMA,CEMB,IGOV,MINC,AGZD,FTSL,SPLV,GHYG,ISTB,ENGN,CMBS,GTIP,SCHO,SMMU,QLTA,SCHZ,HSPX,TUZ,GIY,GSY,TFLO,VMBS,CWB,FLOT,STPZ,MUAC,SCHR,BABZ,HYXU,GMTB,MUNI,WIP,MUAD,QLTB,SCHP,GMMB,MUAE,IPE,NYF,BNDX,MUAF,HYMB,TIPZ,CMF,LAG,ILTB,ITE,CLY,VGSH,VGIT,LTPZ,BABS,HYHG,EMCB,DVYL,VGLT,DHS,TLO,VWOB,IGHG,GLCB,RAVI,VCSH,BSV,BND,BIV,ISHG,SDYL,VCIT,SHY,BLV,HYG,VCLT,TENZ,DTN,BIL,AUD,DLN,DTD,FTSD,CAD,STIP,CORP,HYS,HOLD,TRSY,IEF,IBDA,COBO,BOND,MINT,MBB,CSJ,AGG,SUB,EMB,CIU,GVI,MUB,GBF,TIP,AGZ,CFT,LQD,TLT,IEI,TLH,DIA,BSJF,MONY&types=stats,quote&token=');
//https://cloud.iexapis.com/v1/stock/market/batch?&types=price&symbols=aapl,fb,tsla&token=YOUR_TOKEN_HERE
//https://cloud.iexapis.com/v1/stock/market/batch?&types=quote&symbols=aapl,fb,tsla&token=
// Use the compute function to run parsePhotos in a separate isolate.
//https://cloud.iexapis.com/stable/stock/market/batch?symbols=CNPF,ICOL,PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,PGF,SNLN,DVHL,AUNZ,MDIV,PHB,PFXF,FPE,TIPX,MLN,SDIV,SIPE,SEMF,EMAG,IEMF,EU,BSCM,LEMF,BSCL,BSCK,BSCJ,BSCI,DSUM,BSCF,KBWD,PCEF,BSCG,BSCH,HYEM,ITM,BKLN,PGHY,IBCE,PZT,IJNK,XMPT,THHY,QYLD,IHY,IYLD,SHYD,PRB,DVHI,GOVT,BSJJ,BSJK,RIGS,INY,IBCD,PZA,PFIG,IBCC,BSCE,PVI,MBG,CXA,FWDB,DIV,CHLC,BSJI,FLTR,PWZ,MUAH,IBDD,PICB,IBDB,BSJH,RVNU,BSJG,IBDC,XOVR,BSJE,EBND,PCY,BWX,SJNK,DES,ANGL,BAB,SST,EMCD,CBND,HYD,PLW,SCPB,FLRN,BWZ,KBWY,ELD,IBND,AOK,RWXL,ITR,DON,DGRS,JNK,TZD,EPU,PFF,HYLD,GGOV,ULST,SPHD,HFIN,DGRW,LWC,ALD,LEMB,AGND,ITIP,EMHY,QLTC,TFI,SRLN,HYLS,SHM,GNMA,CEMB,IGOV,MINC,AGZD,FTSL,SPLV,GHYG,ISTB,ENGN,CMBS,GTIP,SCHO,SMMU,QLTA,SCHZ,HSPX,TUZ,GIY,GSY,TFLO,VMBS,CWB,FLOT,STPZ,MUAC,SCHR,BABZ,HYXU,GMTB,MUNI,WIP,MUAD,QLTB,SCHP,GMMB,MUAE,IPE,NYF,BNDX,MUAF,HYMB,TIPZ,CMF,LAG,ILTB,ITE,CLY,VGSH,VGIT,LTPZ,BABS,HYHG,EMCB,DVYL,VGLT,DHS,TLO,VWOB,IGHG,GLCB,RAVI,VCSH,BSV,BND,BIV,ISHG,SDYL,VCIT,SHY,BLV,HYG,VCLT,TENZ,DTN,BIL,AUD,DLN,DTD,FTSD,CAD,STIP,CORP,HYS,HOLD,TRSY,IEF,IBDA,COBO,BOND,MINT,MBB,CSJ,AGG,SUB,EMB,CIU,GVI,MUB,GBF,TIP,AGZ,CFT,LQD,TLT,IEI,TLH,DIA,BSJF,MONY&types=quote,stats&token=
return compute(parsePhotos, response.body);
}
// A function that converts a response body into a List<Photo>.
List<Photo> parsePhotos(String responseBody) {
//final parsed = json.decode(responseBody).cast<Map<String,dynamic>>();
//return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
dynamic Obj = json.decode(responseBody);
debugPrint(responseBody, wrapWidth: 8192);
print(Obj.length);
List<Photo> photoList = [];
Obj.forEach((k, v) => photoList.add(Photo(k,v)));
return photoList;
}
class Photo {
String symbol;
//String companyName;
dynamic data;
// dynamic iexClose;
// dynamic quote;
Photo(this.symbol ,this.data);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appTitle = 'Monthly Paying ETFs';
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('About'),
decoration: BoxDecoration(
color: Colors.grey,
),
),
ListTile(
title: Text('This app is to provide the list of ETF s that pay monthly dividend'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: Text('for questions or feedback please contact me at '),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
appBar: AppBar(
title: Text(title),
backgroundColor: Colors.greenAccent,
),
body: FutureBuilder<List<Photo>>(
future: fetchPhotos(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? PhotosList(photos: snapshot.data)
: Center(child: CircularProgressIndicator());
},
),
);
}
}
class PhotosList extends StatefulWidget {
final List photos;
PhotosList({Key key, this.photos})
: assert(photos != null),
super(key: key);
@override
_PhotosListState createState() => _PhotosListState();
}
class _PhotosListState extends State<PhotosList> {
@override
Widget build(BuildContext context) {
return bodyData();
}
SingleChildScrollView bodyData() =>
SingleChildScrollView(
scrollDirection: Axis.vertical,
// padding: EdgeInsets.all(0.0),
//padding: const EdgeInsets.symmetric(
// padding: new EdgeInsets.fromLTRB(0.001, .001, 1.0, 1.0),
padding: EdgeInsets.all(0.05),
// child: FittedBox(fit:BoxFit.contain,
child:SingleChildScrollView(
scrollDirection: Axis.horizontal,
child:
FittedBox(
fit: BoxFit.fitHeight,
child: DataTable(
// sortColumnIndex: 1,
// sortAscending: true,
columns: <DataColumn>[
DataColumn(
label: Text("Company"),
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) =>
a.data["quote"]["companyName"]
.compareTo(b.data["quote"]["companyName"]));
});
},
),
DataColumn(
label: Text("ttmDivRate"),
numeric: true,
onSort: (_,__) {
setState(() {
widget.photos.sort((a, b) =>
a.data["quote"]["ttmDividendRate"]
.compareTo(b.data["quote"]["ttmDividendRate"]));
});
},
),
DataColumn(
label: Text("Price"),
numeric: true,
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data ["quote"]["latestPrice"]
.compareTo(b.data["quote"]["latestPrice"]));
});
},
),
],
rows: widget.photos
.map(
(photo) =>
DataRow(
cells: [
DataCell(
Text('${photo.data["stats"]["companyName"] ?? ""}'),
),
DataCell(
Text('${photo.data["stats"]["ttmDividendRate"] ?? ""}'),
),
//["quote"]["stats"]
DataCell(
Text('${photo.data["quote"]["stats"]["latestPrice"] ?? ""}')
),
],
),
)
.toList())
),
),
);
}
问题在于值存在,并且在控制台中输出时Flutter说为空。
===================
Launching lib/main.dart on iPhone 11 Pro Max in debug mode...
Running Xcode build...
Xcode build done. 17.9s
Waiting for iPhone 11 Pro Max to report its views...
Debug service listening on ws://127.0.0.1:57768/yyPV-GQyldg=/ws
Syncing files to device iPhone 11 Pro Max...
flutter: {"PGX":{"stats":{"week52change":-0.025465,"week52high":15.28,"week52low":9.71,"marketcap":4595628000,"employees":null,"day200MovingAvg":14.55,"day50MovingAvg":13.39,"float":null,"avg10Volume":2336007.5,"avg30Volume":2648722.77,"ttmEPS":null,"ttmDividendRate":0.8361,"companyName":"Invesco Preferred ETF","sharesOutstanding":324550000,"maxChangePercent":-0.3042,"year5ChangePercent":-0.0367,"year2ChangePercent":-0.0167,"year1ChangePercent":-0.025465,"ytdChangePercent":-0.064111,"month6ChangePercent":-0.045822,"month3ChangePercent":-0.052209,"month1ChangePercent":0.019438,"day30ChangePercent":0.028322,"day5ChangePercent":0.015054,"nextDividendDate":"2020-05-18","dividendYield":0.059046610169491524,"nextEarningsDate":null,"exDividendDate":"2020-05-18","peRatio":null,"beta":0.5684535732534528},"quote":{"symbol":"PGX","companyName":"Invesco Preferred ETF","primaryExchange":"NYSE Arca","calculationPrice":"close","open":14.11,"openTime":1590154200191,"openSource":"official","close":14.16,"closeT<…>
flutter: 2020","latestUpdate":1590177600180,"latestVolume":4747,"iexRealtimePrice":null,"iexRealtimeSize":null,"iexLastUpdated":null,"delayedPrice":11.245,"delayedPriceTime":1590192000004,"oddLotDelayedPrice":11.193,"oddLotDelayedPriceTime":1590173727614,"extendedPrice":11.245,"extendedChange":0.005,"extendedChangePercent":0.00044,"extendedPriceTime":1590186600005,"previousClose":11.16,"previousVolume":8688,"change":0.08,"changePercent":0.00717,"volume":4747,"iexMarketPercent":null,"iexVolume":null,"avgTotalVolume":12262,"iexBidPrice":null,"iexBidSize":null,"iexAskPrice":null,"iexAskSize":null,"iexOpen":null,"iexOpenTime":null,"iexClose":11.04,"iexCloseTime":1589988569572,"marketCap":35406000,"peRatio":null,"week52High":16.6,"week52Low":8.47,"ytdChange":-0.300712,"lastTradeTime":1590177600181,"isUSMarketOpen":false}},"IPFF":{"stats":{"week52change":-0.23383400000000001,"week52high":15.71,"week52low":8.38,"marketcap":28738500,"employees":null,"day200MovingAvg":13.89,"day50MovingAvg":10.96,"float<…>
flutter: 95
flutter: {"PGX":{"stats":{"week52change":-0.025465,"week52high":15.28,"week52low":9.71,"marketcap":4595628000,"employees":null,"day200MovingAvg":14.55,"day50MovingAvg":13.39,"float":null,"avg10Volume":2336007.5,"avg30Volume":2648722.77,"ttmEPS":null,"ttmDividendRate":0.8361,"companyName":"Invesco Preferred ETF","sharesOutstanding":324550000,"maxChangePercent":-0.3042,"year5ChangePercent":-0.0367,"year2ChangePercent":-0.0167,"year1ChangePercent":-0.025465,"ytdChangePercent":-0.064111,"month6ChangePercent":-0.045822,"month3ChangePercent":-0.052209,"month1ChangePercent":0.019438,"day30ChangePercent":0.028322,"day5ChangePercent":0.015054,"nextDividendDate":"2020-05-18","dividendYield":0.059046610169491524,"nextEarningsDate":null,"exDividendDate":"2020-05-18","peRatio":null,"beta":0.5684535732534528},"**quote":{"symbol":"PGX","companyName":"Invesco Preferred ETF","primaryExchange":"NYSE Arca","calculationPrice":"close","open":14.11,"openTime":1590154200191,"openSource":"official","close":14.16,"closeT<…>
flutter: 2020","latestUpdate":1590177600180,"latestVolume":4747,"iexRealtimePrice":null,"iexRealtimeSize":null,"iexLastUpdated":null,"delayedPrice":11.245,"delayedPriceTime":1590192000004,"oddLotDelayedPrice":11.193,"oddLotDelayedPriceTime":1590173727614,"extendedPrice":11.245,"extendedChange":0.005,"extendedChangePercent":0.00044,"extendedPriceTime":1590186600005,"previousClose":11.16,"previousVolume":8688,"change":0.08,"changePercent":0.00717,"volume":4747,"iexMarketPercent":null,"iexVolume":null,"avgTotalVolume":12262,"iexBidPrice":null,"iexBidSize":null,"iexAskPrice":null,"iexAskSize":null,"iexOpen":null,"iexOpenTime":null,"iexClose":11.04,"iexCloseTime":1589988569572,"marketCap":35406000,"peRatio":null,"week52High":16.6,"week52Low":8.47,"ytdChange":-0.300712,"lastTradeTime":1590177600181,"isUSMarketOpen":false}},"IPFF":{"stats":{"week52change":-0.23383400000000001,"week52high":15.71,"week52low":8.38,"marketcap":28738500,"employees":null,"day200MovingAvg":13.89,"day50MovingAvg":10.96,"float<…>
flutter: 95**
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building photorealist(dirty, state: _PhotosListState#8eef8):
The method '[]' was called on null.
Receiver: null
Tried calling: []("iexClose")
============== 列价格为空。 如果我尝试调用“ delayedPrice”:11.552,“ ”或“ iexClose”:11.04。,则它不会在应用程序中打印。
答案 0 :(得分:2)
我检查了您共享的令牌并测试了您共享的代码。
您从错误发生的地方以错误的方式调用了数组。
我尝试过,输出显示无误
DataCell(
Text('${photo.data["quote"]["stats"]["latestPrice"] ?? ""}') //❌
//REPLACE ["quote"]["stats"] with ["stats"]
Text('${photo.data["stats"]["latestPrice"] ?? ""}') //✔️
),
工作代码
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
//import 'package:flutter_web/material.dart';
//import 'package:flutter/main.dart' as app;
//import 'package:flutter_web_ui/ui.dart' as ui;
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
// await client.get('https://cloud.iexapis.com/stable/stock/market/batch?symbols=CNPF,ICOL,PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,IEI,TLH,DIA,BSJF,MONY&types=quote,stats&token=');
await client.get(
'https://cloud.iexapis.com/stable/stock/market/batch?symbols=PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,PGF,SNLN,DVHL,AUNZ,MDIV,PHB,PFXF,FPE,TIPX,MLN,SDIV,SIPE,SEMF,EMAG,IEMF,EU,BSCM,LEMF,BSCL,BSCK,BSCJ,BSCI,DSUM,BSCF,KBWD,PCEF,BSCG,BSCH,HYEM,ITM,BKLN,PGHY,IBCE,PZT,IJNK,XMPT,THHY,QYLD,IHY,IYLD,SHYD,PRB,DVHI,GOVT,BSJJ,BSJK,RIGS,INY,IBCD,PZA,PFIG,IBCC,BSCE,PVI,MBG,CXA,FWDB,DIV,CHLC,BSJI,FLTR,PWZ,MUAH,IBDD,PICB,IBDB,BSJH,RVNU,BSJG,IBDC,XOVR,BSJE,EBND,PCY,BWX,SJNK,DES,ANGL,BAB,SST,EMCD,CBND,HYD,PLW,SCPB,FLRN,BWZ,KBWY,ELD,IBND,AOK,RWXL,ITR,DON,DGRS,JNK,TZD,EPU,PFF,HYLD,GGOV,ULST,SPHD,HFIN,DGRW,LWC,ALD,LEMB,AGND,ITIP,EMHY,QLTC,TFI,SRLN,HYLS,SHM,GNMA,CEMB,IGOV,MINC,AGZD,FTSL,SPLV,GHYG,ISTB,ENGN,CMBS,GTIP,SCHO,SMMU,QLTA,SCHZ,HSPX,TUZ,GIY,GSY,TFLO,VMBS,CWB,FLOT,STPZ,MUAC,SCHR,BABZ,HYXU,GMTB,MUNI,WIP,MUAD,QLTB,SCHP,GMMB,MUAE,IPE,NYF,BNDX,MUAF,HYMB,TIPZ,CMF,LAG,ILTB,ITE,CLY,VGSH,VGIT,LTPZ,BABS,HYHG,EMCB,DVYL,VGLT,DHS,TLO,VWOB,IGHG,GLCB,RAVI,VCSH,BSV,BND,BIV,ISHG,SDYL,VCIT,SHY,BLV,HYG,VCLT,TENZ,DTN,BIL,AUD,DLN,DTD,FTSD,CAD,STIP,CORP,HYS,HOLD,TRSY,IEF,IBDA,COBO,BOND,MINT,MBB,CSJ,AGG,SUB,EMB,CIU,GVI,MUB,GBF,TIP,AGZ,CFT,LQD,TLT,IEI,TLH,DIA,BSJF,MONY&types=stats,quote&token=token_was_added_here');
//https://cloud.iexapis.com/v1/stock/market/batch?&types=price&symbols=aapl,fb,tsla&token=YOUR_TOKEN_HERE
//https://cloud.iexapis.com/v1/stock/market/batch?&types=quote&symbols=aapl,fb,tsla&token=
// Use the compute function to run parsePhotos in a separate isolate.
//https://cloud.iexapis.com/stable/stock/market/batch?symbols=CNPF,ICOL,PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,PGF,SNLN,DVHL,AUNZ,MDIV,PHB,PFXF,FPE,TIPX,MLN,SDIV,SIPE,SEMF,EMAG,IEMF,EU,BSCM,LEMF,BSCL,BSCK,BSCJ,BSCI,DSUM,BSCF,KBWD,PCEF,BSCG,BSCH,HYEM,ITM,BKLN,PGHY,IBCE,PZT,IJNK,XMPT,THHY,QYLD,IHY,IYLD,SHYD,PRB,DVHI,GOVT,BSJJ,BSJK,RIGS,INY,IBCD,PZA,PFIG,IBCC,BSCE,PVI,MBG,CXA,FWDB,DIV,CHLC,BSJI,FLTR,PWZ,MUAH,IBDD,PICB,IBDB,BSJH,RVNU,BSJG,IBDC,XOVR,BSJE,EBND,PCY,BWX,SJNK,DES,ANGL,BAB,SST,EMCD,CBND,HYD,PLW,SCPB,FLRN,BWZ,KBWY,ELD,IBND,AOK,RWXL,ITR,DON,DGRS,JNK,TZD,EPU,PFF,HYLD,GGOV,ULST,SPHD,HFIN,DGRW,LWC,ALD,LEMB,AGND,ITIP,EMHY,QLTC,TFI,SRLN,HYLS,SHM,GNMA,CEMB,IGOV,MINC,AGZD,FTSL,SPLV,GHYG,ISTB,ENGN,CMBS,GTIP,SCHO,SMMU,QLTA,SCHZ,HSPX,TUZ,GIY,GSY,TFLO,VMBS,CWB,FLOT,STPZ,MUAC,SCHR,BABZ,HYXU,GMTB,MUNI,WIP,MUAD,QLTB,SCHP,GMMB,MUAE,IPE,NYF,BNDX,MUAF,HYMB,TIPZ,CMF,LAG,ILTB,ITE,CLY,VGSH,VGIT,LTPZ,BABS,HYHG,EMCB,DVYL,VGLT,DHS,TLO,VWOB,IGHG,GLCB,RAVI,VCSH,BSV,BND,BIV,ISHG,SDYL,VCIT,SHY,BLV,HYG,VCLT,TENZ,DTN,BIL,AUD,DLN,DTD,FTSD,CAD,STIP,CORP,HYS,HOLD,TRSY,IEF,IBDA,COBO,BOND,MINT,MBB,CSJ,AGG,SUB,EMB,CIU,GVI,MUB,GBF,TIP,AGZ,CFT,LQD,TLT,IEI,TLH,DIA,BSJF,MONY&types=quote,stats&token=
return compute(parsePhotos, response.body);
}
// A function that converts a response body into a List<Photo>.
List<Photo> parsePhotos(String responseBody) {
//final parsed = json.decode(responseBody).cast<Map<String,dynamic>>();
//return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
dynamic Obj = json.decode(responseBody);
debugPrint(responseBody, wrapWidth: 8192);
print(Obj.length);
List<Photo> photoList = [];
Obj.forEach((k, v) => photoList.add(Photo(k, v)));
return photoList;
}
class Photo {
String symbol;
//String companyName;
dynamic data;
// dynamic iexClose;
// dynamic quote;
Photo(this.symbol, this.data);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appTitle = 'Monthly Paying ETFs';
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('About'),
decoration: BoxDecoration(
color: Colors.grey,
),
),
ListTile(
title: Text(
'This app is to provide the list of ETF s that pay monthly dividend'),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: Text('for questions or feedback please contact me at '),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
appBar: AppBar(
title: Text(title),
backgroundColor: Colors.greenAccent,
),
body: FutureBuilder<List<Photo>>(
future: fetchPhotos(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? PhotosList(photos: snapshot.data)
: Center(child: CircularProgressIndicator());
},
),
);
}
}
class PhotosList extends StatefulWidget {
final List<Photo> photos;
PhotosList({Key key, this.photos})
: assert(photos != null),
super(key: key);
@override
_PhotosListState createState() => _PhotosListState();
}
class _PhotosListState extends State<PhotosList> {
@override
Widget build(BuildContext context) {
return bodyData();
}
SingleChildScrollView bodyData() => SingleChildScrollView(
scrollDirection: Axis.vertical,
// padding: EdgeInsets.all(0.0),
//padding: const EdgeInsets.symmetric(
// padding: new EdgeInsets.fromLTRB(0.001, .001, 1.0, 1.0),
padding: EdgeInsets.all(0.05),
// child: FittedBox(fit:BoxFit.contain,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: FittedBox(
fit: BoxFit.fitHeight,
child: DataTable(
// sortColumnIndex: 1,
// sortAscending: true,
columns: <DataColumn>[
DataColumn(
label: Text("Company"),
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data["quote"]
["companyName"]
.compareTo(b.data["quote"]["companyName"]));
});
},
),
DataColumn(
label: Text("ttmDivRate"),
numeric: true,
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data["quote"]
["ttmDividendRate"]
.compareTo(b.data["quote"]["ttmDividendRate"]));
});
},
),
DataColumn(
label: Text("Price"),
numeric: true,
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data["quote"]
["latestPrice"]
.compareTo(b.data["quote"]["latestPrice"]));
});
},
),
],
rows: widget.photos
.map(
(photo) => DataRow(
cells: [
DataCell(
Text(
'${photo.data["stats"]["companyName"] ?? ""}'),
),
DataCell(
Text(
'${photo.data["stats"]["ttmDividendRate"] ?? ""}'),
),
//["quote"]["stats"]
DataCell(Text(
'${photo.data["stats"]["latestPrice"] ?? ""}')),
],
),
)
.toList())),
),
);
}
答案 1 :(得分:1)
在响应中,对于某些公司(或符号),quote
的值为null
。
示例(IEMF,欧盟等)
"IEMF": {
"stats": {
"symbol": "IEMF",
"nextDividendDate": null,
"nextEarningsDate": null,
"exDividendDate": null,
"peRatio": null,
"beta": null
},
"quote": null
},
"EU": {
"stats": {
"symbol": "EU",
"nextDividendDate": null,
"nextEarningsDate": null,
"exDividendDate": null,
"peRatio": null,
"beta": null
},
"quote": null
},
检查:
photo.data [“ quote”]!=空
stats
中没有quote
。因此请勿致电photo.data["quote"]["stats"]
使用Text('${photo.data["quote"]["stats"]["latestPrice"] ?? ""}')
代替Text('${(photo.data["quote"] != null ? photo.data["quote"]["latestPrice"] : "") ?? ""}')
完整代码:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
//import 'package:flutter_web/material.dart';
//import 'package:flutter/main.dart' as app;
//import 'package:flutter_web_ui/ui.dart' as ui;
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
// await client.get('https://cloud.iexapis.com/stable/stock/market/batch?symbols=CNPF,ICOL,PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,IEI,TLH,DIA,BSJF,MONY&types=quote,stats&token=');
await client.get(
'https://cloud.iexapis.com/stable/stock/market/batch?symbols=PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,PGF,SNLN,DVHL,AUNZ,MDIV,PHB,PFXF,FPE,TIPX,MLN,SDIV,SIPE,SEMF,EMAG,IEMF,EU,BSCM,LEMF,BSCL,BSCK,BSCJ,BSCI,DSUM,BSCF,KBWD,PCEF,BSCG,BSCH,HYEM,ITM,BKLN,PGHY,IBCE,PZT,IJNK,XMPT,THHY,QYLD,IHY,IYLD,SHYD,PRB,DVHI,GOVT,BSJJ,BSJK,RIGS,INY,IBCD,PZA,PFIG,IBCC,BSCE,PVI,MBG,CXA,FWDB,DIV,CHLC,BSJI,FLTR,PWZ,MUAH,IBDD,PICB,IBDB,BSJH,RVNU,BSJG,IBDC,XOVR,BSJE,EBND,PCY,BWX,SJNK,DES,ANGL,BAB,SST,EMCD,CBND,HYD,PLW,SCPB,FLRN,BWZ,KBWY,ELD,IBND,AOK,RWXL,ITR,DON,DGRS,JNK,TZD,EPU,PFF,HYLD,GGOV,ULST,SPHD,HFIN,DGRW,LWC,ALD,LEMB,AGND,ITIP,EMHY,QLTC,TFI,SRLN,HYLS,SHM,GNMA,CEMB,IGOV,MINC,AGZD,FTSL,SPLV,GHYG,ISTB,ENGN,CMBS,GTIP,SCHO,SMMU,QLTA,SCHZ,HSPX,TUZ,GIY,GSY,TFLO,VMBS,CWB,FLOT,STPZ,MUAC,SCHR,BABZ,HYXU,GMTB,MUNI,WIP,MUAD,QLTB,SCHP,GMMB,MUAE,IPE,NYF,BNDX,MUAF,HYMB,TIPZ,CMF,LAG,ILTB,ITE,CLY,VGSH,VGIT,LTPZ,BABS,HYHG,EMCB,DVYL,VGLT,DHS,TLO,VWOB,IGHG,GLCB,RAVI,VCSH,BSV,BND,BIV,ISHG,SDYL,VCIT,SHY,BLV,HYG,VCLT,TENZ,DTN,BIL,AUD,DLN,DTD,FTSD,CAD,STIP,CORP,HYS,HOLD,TRSY,IEF,IBDA,COBO,BOND,MINT,MBB,CSJ,AGG,SUB,EMB,CIU,GVI,MUB,GBF,TIP,AGZ,CFT,LQD,TLT,IEI,TLH,DIA,BSJF,MONY&types=stats,quote&token=pk_fd71da12cae34ae9abdf3df4958302fe',
);
//https://cloud.iexapis.com/v1/stock/market/batch?&types=price&symbols=aapl,fb,tsla&token=YOUR_TOKEN_HERE
//https://cloud.iexapis.com/v1/stock/market/batch?&types=quote&symbols=aapl,fb,tsla&token=
// Use the compute function to run parsePhotos in a separate isolate.
//https://cloud.iexapis.com/stable/stock/market/batch?symbols=CNPF,ICOL,PGX,MORL,EMLC,GYLD,IPFF,SMB,YDIV,YYY,PEY,PGF,SNLN,DVHL,AUNZ,MDIV,PHB,PFXF,FPE,TIPX,MLN,SDIV,SIPE,SEMF,EMAG,IEMF,EU,BSCM,LEMF,BSCL,BSCK,BSCJ,BSCI,DSUM,BSCF,KBWD,PCEF,BSCG,BSCH,HYEM,ITM,BKLN,PGHY,IBCE,PZT,IJNK,XMPT,THHY,QYLD,IHY,IYLD,SHYD,PRB,DVHI,GOVT,BSJJ,BSJK,RIGS,INY,IBCD,PZA,PFIG,IBCC,BSCE,PVI,MBG,CXA,FWDB,DIV,CHLC,BSJI,FLTR,PWZ,MUAH,IBDD,PICB,IBDB,BSJH,RVNU,BSJG,IBDC,XOVR,BSJE,EBND,PCY,BWX,SJNK,DES,ANGL,BAB,SST,EMCD,CBND,HYD,PLW,SCPB,FLRN,BWZ,KBWY,ELD,IBND,AOK,RWXL,ITR,DON,DGRS,JNK,TZD,EPU,PFF,HYLD,GGOV,ULST,SPHD,HFIN,DGRW,LWC,ALD,LEMB,AGND,ITIP,EMHY,QLTC,TFI,SRLN,HYLS,SHM,GNMA,CEMB,IGOV,MINC,AGZD,FTSL,SPLV,GHYG,ISTB,ENGN,CMBS,GTIP,SCHO,SMMU,QLTA,SCHZ,HSPX,TUZ,GIY,GSY,TFLO,VMBS,CWB,FLOT,STPZ,MUAC,SCHR,BABZ,HYXU,GMTB,MUNI,WIP,MUAD,QLTB,SCHP,GMMB,MUAE,IPE,NYF,BNDX,MUAF,HYMB,TIPZ,CMF,LAG,ILTB,ITE,CLY,VGSH,VGIT,LTPZ,BABS,HYHG,EMCB,DVYL,VGLT,DHS,TLO,VWOB,IGHG,GLCB,RAVI,VCSH,BSV,BND,BIV,ISHG,SDYL,VCIT,SHY,BLV,HYG,VCLT,TENZ,DTN,BIL,AUD,DLN,DTD,FTSD,CAD,STIP,CORP,HYS,HOLD,TRSY,IEF,IBDA,COBO,BOND,MINT,MBB,CSJ,AGG,SUB,EMB,CIU,GVI,MUB,GBF,TIP,AGZ,CFT,LQD,TLT,IEI,TLH,DIA,BSJF,MONY&types=quote,stats&token=
return compute(parsePhotos, response.body);
}
// A function that converts a response body into a List<Photo>.
List<Photo> parsePhotos(String responseBody) {
//final parsed = json.decode(responseBody).cast<Map<String,dynamic>>();
//return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
dynamic obj = json.decode(responseBody);
debugPrint(responseBody, wrapWidth: 1000);
print(obj.length);
List<Photo> photoList = [];
obj.forEach((k, v) => photoList.add(Photo(k, v)));
return photoList;
}
class Photo {
String symbol;
//String companyName;
dynamic data;
// dynamic iexClose;
// dynamic quote;
Photo(this.symbol, this.data);
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appTitle = 'Monthly Paying ETFs';
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
child: ListView(
// Important: Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('About'),
decoration: BoxDecoration(
color: Colors.grey,
),
),
ListTile(
title: Text(
'This app is to provide the list of ETF s that pay monthly dividend',
),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
ListTile(
title: Text(
'for questions or feedback please contact me at ',
),
onTap: () {
// Update the state of the app
// ...
// Then close the drawer
Navigator.pop(context);
},
),
],
),
),
appBar: AppBar(
title: Text(title),
backgroundColor: Colors.greenAccent,
),
body: FutureBuilder<List<Photo>>(
future: fetchPhotos(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? PhotosList(photos: snapshot.data)
: Center(
child: CircularProgressIndicator(),
);
},
),
);
}
}
class PhotosList extends StatefulWidget {
final List photos;
PhotosList({Key key, this.photos})
: assert(photos != null),
super(key: key);
@override
_PhotosListState createState() => _PhotosListState();
}
class _PhotosListState extends State<PhotosList> {
@override
Widget build(BuildContext context) {
return bodyData();
}
SingleChildScrollView bodyData() => SingleChildScrollView(
scrollDirection: Axis.vertical,
// padding: EdgeInsets.all(0.0),
//padding: const EdgeInsets.symmetric(
// padding: new EdgeInsets.fromLTRB(0.001, .001, 1.0, 1.0),
padding: EdgeInsets.all(0.05),
// child: FittedBox(fit:BoxFit.contain,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: FittedBox(
fit: BoxFit.fitHeight,
child: DataTable(
// sortColumnIndex: 1,
// sortAscending: true,
columns: <DataColumn>[
DataColumn(
label: Text("Company"),
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data["quote"]
["companyName"]
.compareTo(b.data["quote"]["companyName"]));
});
},
),
DataColumn(
label: Text("ttmDivRate"),
numeric: true,
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data["quote"]
["ttmDividendRate"]
.compareTo(b.data["quote"]["ttmDividendRate"]));
});
},
),
DataColumn(
label: Text("Price"),
numeric: true,
onSort: (_, __) {
setState(() {
widget.photos.sort((a, b) => a.data["quote"]
["latestPrice"]
.compareTo(b.data["quote"]["latestPrice"]));
});
},
),
],
rows: widget.photos
.map(
(photo) => DataRow(
cells: [
DataCell(
Text(
'${photo.data["stats"]["companyName"] ?? ""}',
),
),
DataCell(
Text(
'${photo.data["stats"]["ttmDividendRate"] ?? ""}',
),
),
//["quote"]["stats"]
DataCell(
Text(
'${(photo.data["quote"] != null ? photo.data["quote"]["latestPrice"] : "") ?? ""}',
),
),
],
),
)
.toList(),
),
),
),
);
}