问题
I am making a mood checker application using flutter where user chose one of 5 emojis to tell their mood. I want to display a PieChart with data emoji vs num of Days it has been chosen. Problem is that I have to fetch data from sqflite Database to get numOfDays a particular emoji is chosen which will be of type Future but charts can't take Futures, I tried to use async-await but it didn't seem to work.
Error
E/flutter (27721): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type 'Future<dynamic>' is not a subtype of type 'int'
E/flutter (27721): #0 _MoodChartState.initData (package:pro_app/journal/view/mood_chart.dart:36:24)
E/flutter (27721): #1 _AsyncAwaitCompleter.start (dart:async/runtime/libasync_patch.dart:49:6)
E/flutter (27721): #2 _MoodChartState.initData (package:pro_app/journal/view/mood_chart.dart:31:16)
E/flutter (27721): #3 _MoodChartState.initState (package:pro_app/journal/view/mood_chart.dart:58:5)
E/flutter (27721): #4 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3846:58)
E/flutter (27721): #5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3711:5)
E/flutter (27721): #6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2956:14)
E/flutter (27721): #7 Element.updateChild (package:flutter/src/widgets/framework.dart:2759:12)
E/flutter (27721): #8 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #9 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #10 StatelessElement.update (package:flutter/src/widgets/framework.dart:3796:5)
E/flutter (27721): #11 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #12 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #13 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #14 ProxyElement.update (package:flutter/src/widgets/framework.dart:4006:5)
E/flutter (27721): #15 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #16 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #17 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #18 ProxyElement.update (package:flutter/src/widgets/framework.dart:4006:5)
E/flutter (27721): #19 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #20 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4601:32)
E/flutter (27721): #21 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4992:17)
E/flutter (27721): #22 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #23 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #24 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #25 StatefulElement.update (package:flutter/src/widgets/framework.dart:3894:5)
E/flutter (27721): #26 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #27 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #28 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #29 ProxyElement.update (package:flutter/src/widgets/framework.dart:4006:5)
E/flutter (27721): #30 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #31 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #32 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #33 StatefulElement.update (package:flutter/src/widgets/framework.dart:3894:5)
E/flutter (27721): #34 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #35 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4883:14)
E/flutter (27721): #36 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #37 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #38 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #39 StatelessElement.update (package:flutter/src/widgets/framework.dart:3796:5)
E/flutter (27721): #40 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #41 SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4883:14)
E/flutter (27721): #42 Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #43 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #44 Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #45 StatefulElement.update (package:flutter/src/widgets/framework.dart:3894:5)
E/flutter (27721): #46 Element.updateChild (package:flutter/src/wid
Mood Model file
import 'package:flutter/material.dart';
class Mood {
int _moodID;
int _emojiID;
int _actID;
int _moodDay;
int _moodMonth;
int _moodYear;
Mood(this._emojiID, this._moodDay, this._moodMonth, this._moodYear,
this._actID);
Mood.withId(this._moodID, this._emojiID, this._moodDay, this._moodMonth,
this._moodYear, this._actID);
int get moodID => _moodID;
int get emojiID => _emojiID;
int get actID => _actID;
int get moodDay => _moodDay;
int get moodMonth => _moodMonth;
int get moodYear => _moodYear;
// can define setters as well
Map<String, int> toMap() {
var map = Map<String, int>();
if (_moodID != null) {
map['moodId'] = _moodID;
}
map['emojiId'] = _emojiID;
map['actId'] = _actID;
map['moodDay'] = _moodDay;
map['moodMonth'] = _moodMonth;
map['moodYear'] = _moodYear;
return map;
}
Mood.fromMap(Map<String, int> map) {
this._moodID = map['moodId'];
this._emojiID = map['emojiId'];
this._actID = map['actId'];
this._moodDay = map['moodMap'];
this._moodMonth = map['moodMonth'];
this._moodYear = map['moodYear'];
}
}
*Database file
import 'package:path/path.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:io';
import '../models/mood_model.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
final String tableName = "moodTable";
final String colMoodId = "moodId";
final String colEmojiId = "emojiId";
final String colActId = "actId";
final String colMoodDay = "moodDay";
final String colMoodMonth = "moodMonth";
final String colMoodYear = "moodYear";
static Database _db;
Future<Database> get db async {
if (_db == null) {
return initDb();
}
return _db;
}
DatabaseHelper.internal();
Future<Database> initDb() async {
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, "mood.db");
var ourDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return ourDb;
}
void _onCreate(Database db, int version) async {
await db.execute(
"CREATE TABLE moodTable (moodId INTEGER PRIMARY KEY, emojiId INTEGER, actId INTEGER, moodDay INTEGER, moodMonth INTEGER, moodYear INTEGER)");
print("Table Created");
}
// insert
Future<int> saveMood(Mood mood) async {
var dbClient = await this.db;
int result = await dbClient.insert("$tableName", mood.toMap());
print('Saved');
return result;
}
// to get number of mood days
Future<List<Map<String, dynamic>>> listOfMoods() async {
Database db = await this.db;
var result = await db.query(tableName, orderBy: '$colMoodId ASC');
return result;
}
Future<int> numOfMoodDays(int emojiID) async {
Database db = await this.db;
var result = await db.query(tableName,
orderBy: '$colMoodId ASC',
where: '$colEmojiId = ?',
whereArgs: [emojiID]);
return result.length;
}
// close db
Future close() async {
var dbClient = await db;
return dbClient.close();
}
}
Mood_Chart file snippet
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
import '../view/mood.dart';
import '../models/mood_db.dart';
import 'dart:async';
class Mood {
String _emoji;
int _numOfDays; // this has to int bcz charts can't take future<int>
charts.Color _color;
Mood(this._emoji, this._numOfDays, this._color);
}
class MoodChart extends StatefulWidget {
@override
_MoodChartState createState() => _MoodChartState();
}
class _MoodChartState extends State<MoodChart> {
DatabaseHelper _databaseHelper = DatabaseHelper();
List<Mood> _data;
List<charts.Series<Mood, String>> _chartData;
// Here I used async-await but this function still return Future<int>
numOfDaysFn(int id) async {
int numOfDays =await _databaseHelper.numOfMoodDays(id);
return numOfDays;
}
void initData() async {
_chartData = List<charts.Series<Mood, String>>();
_data = <Mood>[
Mood(
allMoods[0], numOfDaysFn(1), charts.MaterialPalette.red.shadeDefault),
Mood(allMoods[1], numOfDaysFn(2),
charts.MaterialPalette.blue.shadeDefault),
Mood(allMoods[2], numOfDaysFn(3),
charts.MaterialPalette.gray.shadeDefault),
Mood(allMoods[3], numOfDaysFn(4),
charts.MaterialPalette.indigo.shadeDefault),
Mood(allMoods[4], numOfDaysFn(5),
charts.MaterialPalette.green.shadeDefault),
];
_chartData.add(charts.Series(
id: 'Mood',
data: _data,
colorFn: (Mood mood, _) => mood._color,
domainFn: (Mood mood, _) => mood._emoji,
measureFn: (Mood mood, _) => **mood._numOfDays**, //this can't take futures
));
}
@override
void initState() {
super.initState();
initData();
}
@override
Widget build(BuildContext context) {
return Container(
child: charts.PieChart(
_chartData,
animate: true,
),
);
}
}
List allMoods = ['Disgusting', 'Bad', 'Ok', 'Good', 'Amazing'];
回答1:
I do not know if this code runs because your sample code is not complete. You kinda need to learn how dart futures work. When you call it, the result will return later like Javascript promises
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
import '../view/mood.dart';
import '../models/mood_db.dart';
import 'dart:async';
class Mood {
String _emoji;
int _numOfDays; // this has to int bcz charts can't take future<int>
charts.Color _color;
Mood(this._emoji, this._numOfDays, this._color);
}
class MoodChart extends StatefulWidget {
@override
_MoodChartState createState() => _MoodChartState();
}
class _MoodChartState extends State<MoodChart> {
DatabaseHelper _databaseHelper = DatabaseHelper();
List<Mood> _data;
List<charts.Series<Mood, String>> _chartData = null;
// Here I used async-await but this function still return Future<int>
Future<List<int>> numOfDaysFn(List<int> days) async {
return Future.wait(days.map((d) => _databaseHelper.numOfMoodDays(d)));
}
void initData( List<int> idx, List<int> days) {
setState(() {
_chartData = List<charts.Series<Mood, String>>();
_data = <Mood>[
Mood(
allMoods[idx[0]-1], days[0], charts.MaterialPalette.red.shadeDefault),
Mood(allMoods[idx[1]-1], days[1],
charts.MaterialPalette.blue.shadeDefault),
Mood(allMoods[idx[2]-1], days[2],
charts.MaterialPalette.gray.shadeDefault),
Mood(allMoods[idx[3]-1], days[3],
charts.MaterialPalette.indigo.shadeDefault),
Mood(allMoods[idx[4]-1], days[4],
charts.MaterialPalette.green.shadeDefault),
];
_chartData.add(charts.Series(
id: 'Mood',
data: _data,
colorFn: (Mood mood, _) => mood._color,
domainFn: (Mood mood, _) => mood._emoji,
measureFn: (Mood mood, _) => mood._numOfDays, //this can't take futures
));
});
}
@override
void initState() {
super.initState();
var months = [1,2,3,4,5];
numOfDaysFn(months).then((days) {
initData(months, days);
});
}
@override
Widget build(BuildContext context) {
if(_chartData != null ){
return Container(
child: charts.PieChart(
_chartData,
animate: true,
),
);
} else {
return CircularProgressIndicator();
}
}
}
Revision 1
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
import '../view/mood.dart';
import '../models/mood_db.dart';
import 'dart:async';
class Mood {
String _emoji;
int _numOfDays; // this has to int bcz charts can't take future<int>
charts.Color _color;
Mood(this._emoji, this._numOfDays, this._color);
}
class MoodChart extends StatefulWidget {
@override
_MoodChartState createState() => _MoodChartState();
}
class _MoodChartState extends State<MoodChart> {
DatabaseHelper _databaseHelper = DatabaseHelper();
List<Mood> _data;
List<charts.Series<Mood, String>> _chartData = null;
static List<charts.Color> DEFAULT_SHADE = [
null,
charts.MaterialPalette.red.shadeDefault,
charts.MaterialPalette.blue.shadeDefault,
charts.MaterialPalette.gray.shadeDefault,
charts.MaterialPalette.indigo.shadeDefault,
charts.MaterialPalette.green.shadeDefault];
Future<Mood> numOfDaysFn(int day) async {
return Mood( allMood[day-1] , _databaseHelper.numOfMoodDays(day), DEFAULT_SHADE[day] );
}
Future<List<Mood>> returnAllNumOfDaysFn( List<int> days) async {
return Future.wait(days.map((d) => numOfDaysFn(d)));
}
@override
void initState() {
super.initState();
var months = [1,2,3,4,5];
returnAllNumOfDaysFn(months).then((moods) {
var temp = charts.Series(
id: 'Mood',
data: _data,
colorFn: (Mood mood, _) => mood._color,
domainFn: (Mood mood, _) => mood._emoji,
measureFn: (Mood mood, _) => mood._numOfDays, //this can't take futures
);
setState(() {
_data = moods;
_chartData = temp;
});
});
}
@override
Widget build(BuildContext context) {
if(_chartData != null ){
return Container(
child: charts.PieChart(
_chartData,
animate: true,
),
);
} else {
return CircularProgressIndicator();
}
}
}
https://www.dartlang.org/guides/libraries/futures-error-handling
https://docs.flutter.io/flutter/widgets/State/initState.html
https://www.dartlang.org/tutorials/language/futures#calling-multiple-funcs
Edit: you need to understand setState too
https://docs.flutter.io/flutter/widgets/State/setState.html
Flutter charts provide sample with static data. However, you are fetching data dynamically so you need to call set state.
来源:https://stackoverflow.com/questions/54965567/flutter-passing-futureint-as-int-to-charts